[THUPC2019]令人难以忘记的题目名称
\(\text{Solution}\)
手玩一下,发现如果差分\(k\)次后序列全为零,那么一定存在操作方案使得答案为\(k\)。
那么现在问题就转化成了求最小的\(k\),使得差分\(k\)次后,序列全为\(0\)。
现在考虑去差分\(P^k\)的序列是怎样的,显然新序列\(G\)中\(G_i = S_i + S_{i + P ^ k}\),那么下标在\(mod\) \(n\)的意义下就为\(G_i = S_i + S_{i + \gcd(n, P ^ k)}\)。
现在设\(t\)满足\(P ^ t | n\)且\(P ^ {t + 1} \nmid n\),那么显然如果差分\(P^t\)后序列还是不为\(0\),那么无解。
设答案\(ans\),如果\(ans \le P^{t - 1}\),那么只需保留序列前\(P^{t-1}\)项,否则将序列先差分\(P^{t-1}\),再继续求解,时间复杂度\(O(nP)\)。
\(\text{Code}\)
#include<cstdio>
using namespace std;
const int N = 3e5 + 5;
int a[N], b[N], n, P, pw[N];
int gets(int x) {
if (!x) return 1;
int fl = 0;
for (int i = 0; i < pw[x]; i++)
if (a[i] != a[(i + pw[x - 1]) % pw[x]]) fl = 1;
if (!fl) return gets(x - 1);
for (int j = 1; j <= P; j++) {
for (int i = 0; i < pw[x]; i++)
b[i] = (a[i] - a[(i + pw[x - 1]) % pw[x]] + P) % P;
for (int i = 0; i < pw[x]; i++) a[i] = b[i];
fl = 0;
for (int i = 0; i < pw[x]; i++)
if (a[i] != a[(i + pw[x - 1]) % pw[x]]) fl = 1;
if (!fl) return pw[x - 1] * j + gets(x - 1);
}
}
int main()
{
scanf("%d%d",&n,&P), pw[0] = 1;
int t = 0, g = n, flag = 0;
for (; g % P == 0; g /= P) t++;
for (int i = 1; i <= t; i++) pw[i] = pw[i - 1] * P;
for (int i = 0; i < n; i++) scanf("%d",&a[i]), a[i] %= P;
for (int i = 0; i < n; i++)
if (a[i] != a[(i + pw[t]) % n]) flag = 1;
if (flag) {puts("-1"); return 0;}
printf("%d\n", gets(t));
}

浙公网安备 33010602011771号