Algorithm SPOJ问题FLIBONAKI时限超过

Algorithm SPOJ问题FLIBONAKI时限超过,algorithm,haskell,Algorithm,Haskell,我试图在Haskell解决这个问题,但时间限制超过了。我用我所有的Haskell和数学技巧来优化这个,但都是徒劳的。有人可以建议我如何进一步优化这段代码吗。顺序F_3+F_7+F_11….+F_4n+3)=F_2n*F_2n+1。我用O(logn)来计算斐波那契数 import Data.List import Data.Maybe import qualified Data.ByteString.Lazy.Char8 as BS matmul :: [Integer] -> [Inte

我试图在Haskell解决这个问题,但时间限制超过了。我用我所有的Haskell和数学技巧来优化这个,但都是徒劳的。有人可以建议我如何进一步优化这段代码吗。顺序F_3+F_7+F_11….+F_4n+3)=F_2n*F_2n+1。我用O(logn)来计算斐波那契数

import Data.List
import Data.Maybe
import qualified Data.ByteString.Lazy.Char8 as BS

matmul :: [Integer] -> [Integer] -> Integer -> [Integer]
matmul [a,b,c] [d,e,f] m = [x,y,z] where
    y = (a*e + b*f) `mod` m
    z = (b*e + c*f) `mod` m
    x = y + z


powM ::[Integer] -> Integer -> Integer -> [Integer]
powM a n m | n == 1 = a 
   | n == 2 = matmul a a m
   | even n = powM ( matmul a a m ) ( div n 2 ) m 
   | otherwise = matmul a ( powM ( matmul a a m ) ( div n 2 ) m ) m 

readInt :: BS.ByteString -> Integer
readInt  = fst.fromJust.BS.readInteger 

solve::Integer -> BS.ByteString
solve n = BS.pack.show $ mod ( c*d ) 1000000007 where 
 [c,d,_] = powM [1,1,0] ( 2*n ) 1000000007
--([_,a,_]:_) = powM [[1,2,1],[0,5,3],[0,3,2]] n 1000000007
-- f_3+f_7+f_11+f_15 = f_2n*f_(2n+1)

main = BS.interact $ BS.unlines. map ( solve.readInt ) . tail . BS.lines 

您的求解速度似乎足够快,但您的主函数似乎没有在每一行之后打印答案。事实上,它需要一个额外的换行符才能得到最后的答案,所以这可能是你超时的原因!这是一个直接在输入后打印每个答案的版本

import Data.List
import Data.Maybe
import Control.Monad
import qualified Data.ByteString.Lazy.Char8 as B
import qualified Data.ByteString.Char8 as BC
import qualified Text.Show.ByteString as BS

matmul :: [Integer] -> [Integer] -> Integer -> [Integer]
matmul [a,b,c] [d,e,f] m = [x,y,z] where
    y = (a*e + b*f) `mod` m
    z = (b*e + c*f) `mod` m
    x = y + z

powM :: [Integer] -> Integer -> Integer -> [Integer]
powM a n m | n == 1 = a 
   | n == 2 = matmul a a m
   | even n = powM ( matmul a a m ) ( div n 2 ) m 
   | otherwise = matmul a ( powM ( matmul a a m ) ( div n 2 ) m ) m 

solve :: Integer -> Integer
solve n = mod ( c*d ) 1000000007 
  where 
  [c,d,_] = powM [1,1,0] ( 2*n ) 1000000007

readInteger :: B.ByteString -> Integer
readInteger  = fst . fromJust . B.readInteger

readInt :: B.ByteString -> Int
readInt = fst . fromJust . B.readInt

get :: IO B.ByteString
get = liftM (B.fromChunks . (:[])) BC.getLine

main :: IO ()
main = do
  n <- liftM readInt get
  replicateM_ n ( liftM readInteger get >>= B.putStrLn . BS.show . solve )
导入数据。列表
导入数据,也许吧
进口管制
将限定数据.ByteString.Lazy.Char8作为B导入
将符合条件的Data.ByteString.Char8作为BC导入
将限定的Text.Show.ByteString作为BS导入
matmul::[Integer]->[Integer]->Integer->[Integer]
matmul[a,b,c][d,e,f]m=[x,y,z]其中
y=(a*e+b*f)`mod`m
z=(b*e+c*f)`mod`m
x=y+z
powM::[Integer]->Integer->Integer->[Integer]
功率a n m | n==1=a
|n==2=matmul a m
|偶数n=功率(matmul a m)(第2部分)m
|否则=matmul a(功率(matmul a m)(分区n 2)m)m
求解::整数->整数
求解n=mod(c*d)100000007
哪里
[c,d,_]=powM[1,1,0](2*n)100000007
readInteger::B.ByteString->Integer
readInteger=fst。从刚才开始。B.readInteger
readInt::B.ByteString->Int
readInt=fst。从刚才开始。B.readInt
get::IO B.ByteString
get=liftM(B.fromChunks.(:[])BC.getLine
main::IO()
main=do
n>=B.putStrLn。BS.show。解决)

当您使用时间分析时,哪些函数占用的时间最多?haskell中没有人解决过这一问题,可能是它对这个问题来说太慢了。也许一点记忆会有所帮助。对于堆栈溢出,一点严格的注释通常是解决方案。我认为问题不在于haskell,而在于ghc-6.10,这是SPOJ使用的版本。我无法用ghc-6.12.3复制堆栈溢出,这是我可用的最古老的Haskell,但它比ghc-7慢得多。您可以尝试在
matmul
中的列表模式中添加bang模式,这可能就是thunk的形成之处。