社区讨论
30pts Haskell 有无优化空间
P5137 polynomial参与者 2已保存回复 1
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @lo27uac4
- 此快照首次捕获于
- 2023/10/23 09:25 2 年前
- 此快照最后确认于
- 2023/11/03 09:39 2 年前
退役之后稍微学了些 Haskell,感觉函数式编程写这种数学题应该没有大问题,但是两版代码一个 WA 30pts 一个 TLE 30pts,前者用了
Int(只有 64 位,会爆),后者用了 Integer(高精,会 T)。然后我搜了搜,好像 Haskell 还没有类似 C++ 的那种 long double 可以用来写快速乘。过来请教洛谷大佬们有无优化空间,能把这个代码改成 AC 的。下面这份代码是我说的 TLE 的代码,供各位查阅:
HASKELL{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE Strict, MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies, BangPatterns #-}
import qualified Data.ByteString.Char8 as C
import Control.Applicative
import Data.Array
import Data.Bits
int :: C.ByteString -> Int
int s = let Just (n, _) = C.readInt s in n
readInt :: IO Int
readInt = int <$> C.getLine
integer :: C.ByteString -> Integer
integer s = let Just (n, _) = C.readInteger s in n
readIntegers :: IO [Integer]
readIntegers = map integer . C.words <$> C.getLine
replicateTransitionM :: Monad m => Int -> a -> (a -> m a) -> m a
replicateTransitionM 0 x _ = return x
replicateTransitionM n x f = f x >>= \y -> replicateTransitionM (n - 1) y f
replicateTransitionM_ :: Monad m => Int -> a -> (a -> m a) -> m ()
replicateTransitionM_ n x f = replicateTransitionM n x f >> return ()
-- Z3 a = {alpha, beta, gamma, p}
data Z3 a = MatrixSimplified a a a a
infixl 5 >*<
(>*<) :: (Integral a) => Z3 a -> Z3 a -> Z3 a
f0@(MatrixSimplified alpha0 beta0 gamma0 p0) >*< f1@(MatrixSimplified alpha1 beta1 gamma1 p1)
| p0 /= p1 = error "Failed to calculate the product of Z3's with different modules"
| otherwise = MatrixSimplified alpha beta gamma p
where
alpha = mod (alpha0 * alpha1) p0
beta' = (mod (beta0 * alpha1) p0) + (mod (gamma0 * beta1) p0)
beta = if beta' >= p0 then beta' - p0 else beta'
gamma = mod (gamma0 * gamma1) p0
p = p0
infixl 5 >!<
(>!<) :: (Integral a) => Z3 a -> Int -> a
f0@(MatrixSimplified alpha beta gamma p) >!< t
| t == 0 = alpha
| t == 1 = beta
| t == 2 = gamma
| otherwise = error "Failed to fetch an element of Z3"
calcExp :: (Integral a) => Z3 a -> Z3 a -> Integer -> a
calcExp f0 f1 t = (calcExp' f0 f1 t) >!< 1
where
calcExp' _ f1 0 = f1
calcExp' f0 f1 t
| even t = calcExp' (f0 >*< f0) f1 (shiftR t 1)
| otherwise = calcExp' (f0 >*< f0) (f1 >*< f0) (shiftR t 1)
main :: IO ()
main = do
t <- readInt
replicateTransitionM_ t 0 $ \x -> do
[n, a, b, p] <- readIntegers
let [f0, f1] = [MatrixSimplified a (toInteger 1) b p, MatrixSimplified (toInteger 0) (toInteger 1) b p]
(putStrLn $ show (calcExp f0 f1 n)) >> (return 0)
return ()
我知道 Haskell 本身性能是不如 C++ 的,但是感觉性能差距大概也就两倍吧,我用了题解的 Memory_of_winter 的矩阵快速幂方法写了 C++ 代码,最慢的点跑了不到 380ms,×2 就是不到 760ms,感觉 Haskell 也有戏……
回复
共 1 条回复,欢迎继续交流。
正在加载回复...