传送门
Solution
设 A0 所有元素之和为 sum。
若 sum≤0 ,答案为 0。
若 sum>0,因为 A0 各项均不大于 1,则一定存在 k,使得 A0 经过 k 次循环左移后,A0 是安全的,且此时可把 A0 分为 sum 块,每一块的元素之和都恰好为 1。以样例循环左移三次后为例:
此时两部分之和分别都为 1。
所以对于满足 sum>0 的任意 A0,其实可以把它分成 sum 块整体,循环左移时一块一块地捆绑在一起。这样 A0 循环左移的结果只有 sum 种,且显然它们都是安全的数列。而且易证对于确定的 A0,捆绑的方式只有一种,循环左移后的数列也只有 sum 个是安全的。
设 Ai 的长度为 pi 倍的 A0,取 p0=1,有
pi+1=pi2sum
这个递推公式可以通过手玩得到。由它又可推出答案
pipi+1=sum2k
设 M=998244353,因为 k 最大为 106,且要对 M 取模,用扩展欧拉定理可得
pipi+1=sum2k=sum2kmodM−1modM
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <bits/stdc++.h> using namespace std; typedef long long ll;
const ll N = 1e6 + 10, mod = 998244353;
ll n, a[N], k, sum[N], ans = 0, low, cnt, len, minn[N], mini, tot; priority_queue<int> q;
ll qpow(ll a, ll b, ll p) { ll res = 1; while (b) { if (b & 1) res = res * a % p; a = a * a % p; b >>= 1; } return res; }
int main() { scanf("%lld%lld", &n, &k); len = 1; for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); sum[i] = sum[i - 1] + a[i]; } if (sum[n] <= 0) { printf("0"); return 0; } printf("%lld", qpow(sum[n], qpow(2, k, mod - 1), mod)); return 0; }
|