P8704 [蓝桥杯 2020 省 A1] 填空问题 题解
SAMSHAWCRAFT · · 题解
我 XCPC 的队友要打蓝桥杯,他做到这个题的 E 的时候和我说他怎么也做不出来这个题。我后来一看标答数据和里面的 E 题答案是
A 题
我们可以写一个函数模拟这个过程。定义 tick 是跑步-休息或休息-跑步转换的时刻对应的分钟数,当 tick 是偶数时,当前是全过程开始(对应 tick 是 tick 是其它偶数的情况),分类讨论,如果当前体力值 stamina 大于 tick 是奇数时,直接给体力值 stamina 加上
注意到本题题面中写到了:为了使答案为整数,以秒为单位输出答案。所以这里使用了 round 对答案取整,答案为
{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE Strict, MultiParamTypeClasses, FlexibleInstances #-}
import Control.Monad
import System.IO
exercise :: Double
exercise = exerciseWith 10000 600 300 0
where
exerciseWith :: Double -> Double -> Double -> Integer -> Double
exerciseWith stamina decRate incRate tick
| even tick =
if stamina >= decRate
then exerciseWith (stamina - decRate) decRate incRate (tick + 1)
else fromIntegral tick * 60 + stamina * 60 / decRate
| otherwise = exerciseWith (stamina + incRate) decRate incRate (tick + 1)
main :: IO()
main = do
(print . round) exercise
B 题
混检一共可以分成两步,第一步是检测
考察这两种取值的概率,设单人检测的结果为阳性的概率(意即题目中的感染率)为
化简得
个试剂盒,代入
因此本人认为答案应该为
我注意到其它题解另有计算出
C 题
我们可以使用搜索的方法完成这个问题,对于每一批口罩,都有两种分配方法,使用递归函数枚举所有分配方法(共
{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE Strict, MultiParamTypeClasses, FlexibleInstances #-}
import Control.Monad
import System.IO
masks :: [Integer]
masks = [9090400,8499400,5926800,8547000,4958200,4422600,5751200,4175600,6309600,5865200,6604400,4635000,10663400,8087200,4554000]
distribute :: Integer
distribute = distributeWith masks 0 0
where
distributeWith :: [Integer] -> Integer -> Integer -> Integer
distributeWith masks alphaMasks betaMasks
| null masks = abs (alphaMasks - betaMasks)
| otherwise = min (distributeWith (tail masks) (alphaMasks + head masks) betaMasks) (distributeWith (tail masks) alphaMasks (betaMasks + head masks))
main :: IO()
main = do
print distribute
D 题
本题等价于问
{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE Strict, MultiParamTypeClasses, FlexibleInstances #-}
import Control.Monad
import System.IO
arrange :: Integer
arrange = mod (arrangeWith 1010) 2020
where
arrangeWith :: Integer -> Integer
arrangeWith 0 = 1
arrangeWith x = div ((4 * x - 2) * arrangeWith (x - 1)) (x + 1)
main :: IO()
main = do
print arrange
E 题
我们面对这种有关于数字当中每一位的性质的题其实没有太多的解决办法,数论上并没有什么捷径可以直接求出第
所以说这种问题目前来说只能是搜索解决,我这里提供一个逐步优化的思路。首先我们写一个最幼稚的搜索代码,直接枚举每一个数字,然后判断它的每一位是不是完全平方数:
{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE Strict, MultiParamTypeClasses, FlexibleInstances #-}
import Control.Monad
import System.IO
square :: Integer -> Integer
square x = x * x
checkDigit :: Integer -> Bool
checkDigit x
| x >= 10 = checkDigit (div x 10) && checkSingleDigit (mod x 10)
| otherwise = checkSingleDigit x
where
checkSingleDigit :: Integer -> Bool
checkSingleDigit x
| x == 0 || x == 1 || x == 4 || x == 9 = True
| otherwise = False
replicateTransitionM :: Monad m => Int -> a -> (a -> Bool) -> (a -> m a) -> m a
replicateTransitionM 0 x _ _ = return x
replicateTransitionM n x g f
| g x = f x >>= \y -> replicateTransitionM (n - 1) y g f
| otherwise = f x >>= \y -> replicateTransitionM n y g f
main :: IO ()
main = do
replicateTransitionM 2020 0 (checkDigit . square) $ \x -> do
when ((checkDigit . square) x) ((print . square) x) >> return (x + 1)
>> return ()
我们思考这样一个问题,题目要求的数字是不是有什么特殊性质?最容易想到的是个位数字只能是
{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE Strict, MultiParamTypeClasses, FlexibleInstances #-}
import Control.Monad
import System.IO
square :: Integer -> Integer
square x = x * x
-- 0 ^ 2 = 0, 1 ^ 2 = 1, 2 ^ 2 = 4, 3 ^ 2 = 9, 4 ^ 2 = 6
-- 5 ^ 2 = 5, 6 ^ 2 = 6, 7 ^ 2 = 9, 8 ^ 2 = 4, 9 ^ 2 = 1
-- if x mod 10 = 3 then the next candidate is some y mod 10 = 7
succRCandidate :: Integer -> Integer
succRCandidate x
| mod x 10 == 3 = x + 4
| otherwise = x + 1
checkDigit :: Integer -> Bool
checkDigit x
| x >= 10 = checkDigit (div x 10) && checkSingleDigit (mod x 10)
| otherwise = checkSingleDigit x
where
checkSingleDigit :: Integer -> Bool
checkSingleDigit x
| x == 0 || x == 1 || x == 4 || x == 9 = True
| otherwise = False
replicateTransitionM :: Monad m => Int -> a -> (a -> Bool) -> (a -> m a) -> m a
replicateTransitionM 0 x _ _ = return x
replicateTransitionM n x g f
| g x = f x >>= \y -> replicateTransitionM (n - 1) y g f
| otherwise = f x >>= \y -> replicateTransitionM n y g f
main :: IO ()
main = do
replicateTransitionM 2020 0 (checkDigit . square) $ \x -> do
when ((checkDigit . square) x) ((print . square) x) >> return (succRCandidate x)
>> return ()
我们接着还可以优化,注意到一个完全平方数后两位只可能是某 succRCandidate 函数,从而减少搜索范围。
这 succRCandidate 的部分),就不放了。
本题答案为 __int128 或者高精度等防止溢出的方法。