Link
利用归纳法可以推出这样的一个结论:(k)轮之后胜利当且仅当(S)恰好差分(k)次之后变成全(0)序列。
我们知道差分(t)次之后(Delta^tS_i=sumlimits_{k=0}^t(-1)^k{tchoose k}S_{i+k}),因此(Delta^{p^k}S_i=S_i-S_{i+p^k})。
那么我们先找到一个最小的(t=p^k),满足(S_i=S_{i+t}),这相当于(S_i=S_{i+gcd(t,n)})。
设(p^a|n),若(S)的(p^a)阶差分不是全(0)序列,那么一定无解,否则一定有解。
那么现在我们可以只保留(S)的前(p^a)项。
设答案为(ans),且(ansle p^{a-1}),那么此时(S)一定是有一个循环节(p^{a-1})。
否则我们对(S)进行(p^{a-1})阶差分直到(S)满足以(p^{a-1})为循环节即可。
时间复杂度为(O(np))。
#include<cctype>
#include<cstdio>
#include<cstring>
const int N=300007;
int n,p,t,ans,a[N],b[N];
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
int check(int p)
{
for(int i=0;i<n;++i) if(a[i]^a[(i+p)%n]) return 0;
return 1;
}
int main()
{
n=read(),p=read(),t=1;
for(int i=0;i<n;++i) a[i]=read()%p;
while(!(n%(t*p))) t*=p;
if(!check(t)) return puts("-1"),0;
for(n=t;n^1;n=t) for(t=n/p;!check(t);memcpy(a,b,4*n),ans+=t) for(int i=0;i<n;++i) b[i]=(a[i]-a[(i+t)%n]+p)%p;
printf("%d",ans+!!a[0]);
}