[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));
}
posted @ 2022-10-28 10:55  RiverSheep  阅读(26)  评论(0)    收藏  举报