0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ABC254 A~E をHaskellで

Posted at

A - Last Two Digits

問題 ABC254A

シグネチャを決めるまでもない。必ず3桁な入力を整数として解釈したら負けである。

結果

main = getLine >>= putStrLn . tail

B - Practical Computing

問題 ABC254B

シグネチャを決める。

abc254b :: Int -> [[Int]]

これはパスカルの三角形、または二項係数そのものであるが、たかだか $N \leq 30$ なので問題文どおりに生成する。

結果

abc254b n = take n ncrs

ncrs = [1] : map step ncrs

step ncr = zipWith (+) (0 : ncr) (ncr ++ [0])

C - K Swap

問題 ABC254C

シグネチャを決める。

abc254c :: Int  -> Int   -- N, K
        -> [Int]         -- ai
        -> Bool          -- 結果

添え字を0始まりにして考える。
どのように操作を行っても、数列の $i$ 番目の要素は、$K$ 間隔の位置である $i + nK$ 番目($n$ は負を含む任意の整数)にしか来ることができない。
つまり、$A$ を $K$ 間隔で取り出した多重集合 $A_j = \{ a_{nK+j} \;|\; n = 0,1\dots \} \; (0 \leq j < K)$ と、$A$ を整列した列 $S = (s_1, s_2, \dots, s_N)$ を $K$ 間隔で取り出した多重集合 $S_j = \{ s_{nK+j} \;|\; n = 0,1,\dots \} \; (0 \leq j < K)$ が、$A_j = S_j \; (0 \leq j < K)$ である必要がある。

結果

import Data.List
import Data.Function

abc254c :: Int -> Int -> [Int] -> Bool
abc254c n k as = and $ zipWith ((==) `on` sort) ds es
  where
    f = transpose . chop k
    ds = f        as
    es = f $ sort as

chop :: Int -> [a] -> [[a]]
chop n = unfoldr step
  where
    step [] = Nothing
    step xs = Just $ splitAt n xs

chopData.List.Split の関数であるが、import すると怒られた。

D - Together Square

問題 ABC254D

シグネチャを決める。

abc254d :: Int -> Int

公式解説、ユーザ解説が非常に豊富にあるのでそちらも参照して。

素数を $[P_i]$ とする。数を素因数分解して考える。
任意の整数 $t = \prod P_i^{T_i}$ に対して、$t^2 = \prod P_i^{2 T_i}$ である。すなわち、平方数はべき乗の数がすべて偶数である。
この事実をもとに考えると、$a = \prod P_i^{A_i}$ と掛け合わせたら平方数になるような数 $b = \prod P_i^{B_i}$ は、$a \times b = \prod P_i^{A_i + B_i}$ について、$A_i + B_i$ が全て偶数である必要がある。つまり、$A_i$ と $B_i$ の偶奇が全て同じとなるような $b$ の個数だけ、$a$ と掛け合わせたら平方数となる数がある。

よって、べき乗の数の偶奇パターン全て $[偶,偶,\dots] \sim [奇,奇,\dots]$ について、$1 \leq i \leq N$ にそのような数がいくつあるかを数えられれば、その個数の二乗の和が答えである。

偶奇パターンを網羅しようとすると、$N$ 以下の最大の素数が $P_c$ であるときパターンは長さ $c$ になる。$2 \times 10^5$ 以下の素数は17984個もあるので、長さ17984の [Bool] で表すか、ビット列に落とし込んでも $0 \sim 2^{17984}-1$ の整数でこれを表現するには Int では収まらない。(なお、力づくで Integer で表して Map で数えて AC することもできる。

しかしよく考えると、$P_{17983} \cdot P_{17984} > 2 \times 10^5$ のように、全てのビット列が現れるわけではないので、べき乗の数が奇数な素数だけの積で代表させることができる。つまり $t = \prod P_i^{T_i}$ であるとき、$N(t) = \prod P_i^{T_i \bmod 2}$ とする。これは $t \geq N(t)$ なので Int で扱える。

素因数分解は作り置きのスニペットを使う。

結果

import Data.Array.Unboxed
import Data.List

abc254d :: Int -> Int
abc254d n = sum . map (^ 2) . elems arr
  where
    arr :: UArray Int Int
    arr = accumArray (+) (1,n) [(norm i, 1) | i <- [1 .. n]]

norm :: Int -> Int -- 関数 N
norm = product . map head . filter (odd . length) . group . primeFactors

-- @gotoki_no_joe
primeFactors :: Int -> [Int]
primeFactors n = loop n pprimes
  where
    pprimes = 2 : 3 : [y | x <- [5,11..], y <- [x, x + 2]]  -- pseudo primes
    loop n pps@(p:ps)
      | n == 1    = []
      | n < p * p = [n]
      | r == 0    = p : loop q pps
      | otherwise = loop n ps
      where
        (q,r) = divMod n p

続き

ひとつめの公式解説で言っている $\frac{i}{f(i)}$ は上の $N(\cdot)$ と同じものである。
$f(i)$ を高速に求めるために、候補となる $i$ 以下の平方数の降順のリストを素早く取り出せる sqm :: IntMap [Int] を作った。

import qualified Data.IntMap as IM
import Data.List
import Data.Maybe
import Data.Array.Unboxed

abc254d :: Int -> Int
abc254d n = sum $ map (^2) $ elems arr
  where
    arr :: UArray Int Int
    arr = accumArray (+) 0 (1,n) [(idivfi i, 1) | i <- [1..n]]

    sqs = reverse $ takeWhile (n >=) $ map (^ 2) [1 ..]
    sqm = IM.fromAscList $ reverse [(head sq, sq) | sq <- init $ tails sqs]
    idivfi i = head
      [ q
      | sq <- snd $ fromJust $ IM.lookupLE i sqm
      , let (q,r) = divMod i sq
      , r == 0]

結果、素因数分解した方が速かった。

E - Small d and k

問題 ABC254E

シグネチャを決める。

abc254e :: Int -> Int   -- N,M
        -> [(Int,Int)]  -- (ai,bi)
        -> Int          -- Q
        -> [(Int,Int)]  -- (xi,ki)
        -> [Int]        -- 答え

グラフの問題と聞いて身構えてしまうが、問題文に太字で「各頂点の次数は3以下」とヒントが書いてある。また、毎回のクエリで聞かれる距離も $0 \leq k_i \leq 3$ と小さい。
出発点 $x_i$ から距離1の頂点は、次数が3として3個、そこから距離1の頂点は次数3のうち $x_i$ でないものはもう2個、さらに距離1の頂点はもう2個で、$1 + 3 + 3 \times 2 + 3 \times 2 \times 2 = 22$ 頂点しかない。親を除くのをさぼっても $1 + 3 + 3 \times 3 + 3 \times 3 \times 3 = 40$ しかないので、力づくで挙げてしまえば済む。

結果

import Data.Array
import Data.List

abc254e :: Int -> Int -> [(Int,Int)] -> Int -> [(Int,Int)] -> [Int]
abc254e n m abs q xks = map (query g) xks
  where
    g = accumArray (flip (:)) [] (1,n) [p | (a,b) <- abs, p <- [(a,b),(b,a)]]

query g (x,k) = sum $ nub $ concat $ take (succ k) $ iterate (concatMap (g !)) [x]
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?