传送门
题解:
倒着思考,什么样的序列必胜?首先是全0序列,然后是全等序列,然后是差分后是全等序列的。。。以此类推,必胜的序列必然满足它的某一阶差分在 %p 下是全0,且最少的差分次数就是答案。
以下将差分定义为 A i ′ = A i − A i + 1 A'_i=A_i-A_{i+1} Ai′=Ai−Ai+1,这里省略了下标的取模,默认 A A A 是一个循环序列。
首先我们知道一个差分后是数列可以写成 A i ′ = ∑ j = 0 t ( t j ) ( − 1 ) j A i + j A'_i=\sum_{j=0}^t{t\choose j}(-1)^jA_{i+j} Ai′=j=0∑t(jt)(−1)jAi+j
考虑 t = p k t=p^k t=pk 的情况,用 Lucas 定理消去为0的组合数,我们发现这个时候 A i ′ = A i − A i + p k A'_i=A_i-A_{i+p^k} Ai′=Ai−Ai+pk。
假设 A A A 能够最终差分为全 0 0 0,次数为 a a a,则必然存在某个 p k ≥ a p^k\geq a pk≥a,使得差分 p k p^k pk 之后序列为全0,则 A i ′ = 0 = A i − A i + p k A'_i=0=A_i-A_{i+p^k} Ai′=0=Ai−Ai+pk,即 A i = A i + p k A_i=A_{i+p^k} Ai=Ai+pk。
我们发现限制容易变成 A i = A i + gcd ( n , p k ) A_i=A_{i+\gcd(n,p^k)} Ai=Ai+gcd(n,pk),那么将 k k k 变大我们发现最大只需要考虑 p k ∣ n , p k + 1 ∤ n p^k|n,p^{k+1}\nmid n pk∣n,pk+1∤n,再往上就没有意义了,这个时候看一下原序列是否满足条件,满足则有解,否则无解。
求答案就很简单了,我们把 n n n 变为循环节长度 p k p^k pk,考虑进行若干次 p k − 1 p^{k-1} pk−1 次差分,直到循环节长度变为 p k − 1 p^{k-1} pk−1,可以证明复杂度上界是等比数列求和为 O ( n , p ) O(n,p) O(n,p)。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}
}using namespace IO;
using std::cerr;
using std::cout;
cs int N=3e5+7;
int n,p;
int A[N],B[N];
bool check(int t){
for(int re i=0;i+t<n;++i)
if(A[i]!=A[i+t])return false;
return true;
}
void Main(){
n=gi(),p=gi();
for(int re i=0;i<n;++i)
A[i]=gi()%p;
int t=1;
while(n%(t*p)==0)t*=p;
if(!check(t)){
puts("-1");
return ;
}int ans=0;
while(t>1){
n=t;t/=p;
while(!check(t)){ans+=t;
for(int re i=0;i<n;++i)
B[i]=(A[i]-A[(i+t)%n]+p)%p;
memcpy(A,B,sizeof(int)*n);
}
}cout<<ans+!!A[0]<<"\n";
}
inline void file(){
#ifdef zxyoi
freopen("game.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}