公式解説
imoscon_o 解説
が の倍数となるような の求め方
このとき, と の で割った余りはどちらも等しいため,C++の場合は以下のようにして求まります.
ちなみに,なぜこのような書き方をしなければならないのかというと,C++は負の数を正の数で割った余りが負の数として返ってきてしまうためです.
なお,Pythonの場合は を で割った余りがそのまま となるようです.
また,この問題を解くうえで割り算を必要とする過程がありますが,modulo演算において,割り算は特殊な条件を満たさなければ合法な操作として認められません.代わりに逆元を掛け合わせることで期待された効果を得ることができます.ここでは, が素数であることを利用することでフェルマーの最終定理を用いて逆元を高速に求めることができます.
小課題1
Imos操作の逆操作はなにかについて考えます.逆操作とは,Imos操作をした後の数列が与えられたときに,逆操作を行うと元の数列が分かるような操作の事です.
ここで,正整数列 に 度だけImos操作を施した後の数列を とおくと,以下の等式が成立します.
したがって, 以上 以下の整数 について, が成立するので,これがImos操作の逆操作に当たります.
これは で実装できるので,この小課題を解くことができました.
また,これにより逆操作が つに定まるため,答えるべき数列が つしか存在しないことの証明も完了します.
小課題2
正でない整数 について, として,以下のことを示します.
数列 に対して,Imos操作の逆操作を 回行った後の数列を とするとき,
である.
(証明)
(i) のとき
より成立.
(ii) のとき成立するとして, のとき
このとき,
が成り立つことから,
と変形することができるので,これで題意は示せた.■
したがってこの問題は で解くことができます.
回答例(C++)
#include<bits/stdc++.h> #define rep(i, n) for (int i = 0; i < n; i++) using namespace std; const long long mod = 998244353; long long inverse(long long x) { long long ret = 1; int y = mod - 2; while (y > 0) { if (y % 2 == 1) { ret = ret * x % mod; } x = x * x % mod; y >>= 1; } return ret; } int main() { int n, m, k; cin >> n >> m >> k; vector<int> vec(n); rep(i, n) cin >> vec[i]; long long ans = 0; long long pm = 1; long long combi = 1; rep(i, k + 1) { int num = 0; if (m - 1 - i >= 0) num = vec[m - 1 - i]; ans += pm * combi * num; ans = (ans % mod + mod) % mod; pm *= -1; combi = (combi * (k - i)) % mod; combi = (combi * inverse(i + 1)) % mod; } cout << ans << endl; return 0; }
回答例(Python)
import math import bisect import collections import heapq mod = 998244353 def inverse(x): ret = 1 y = mod - 2 while y > 0: if y % 2 == 1: ret = ret * x % mod x = x * x % mod y >>= 1 return ret def main(): n,m,k = map(int,input().split()) vec = list(map(int,input().split())) ans = 0 pm = 1 combi = 1 for i in range(k+1): num = 0 if (m - 1 - i >= 0): num = vec[m - 1 - i] ans += pm * combi * num ans %= mod pm *= -1 combi = combi * (k - i) % mod combi = combi * inverse(i + 1) % mod print(ans) return main()