CF763C Timofey and remoduling
CF763C Timofey and remoduling
Description
给出 \(m,n\)(\(m\) 为质数),以及一个长度为 \(n\) 的数列 \(A\)。请你任意重排 \(A\) 的顺序,使得 \(A\) 是一个模 \(m\) 意义下的等差数列。
即,存在非负整数 \(0\leq s,d < m\) 使得对于 \(1 \leq i \leq n\) 都满足 \(a_i=(s+(i-1)d)\bmod m\)。
如果可行,输出任意一组 \(s,d\) 的值;否则输出 \(-1\)。
Solution
首先有一个 \(O(n^2)\) 做法:钦定 \(A_1\) 为开头,枚举下一个元素 \(A_i\),那么公差为 \(A_i-A_1\)。暴力向前向后扩展。
上面做法的缺陷在于需要枚举公差。考虑能不能直接计算出这个公差。
先假设有解。设数列 \(A\) 由数列 \(B\) 模 \(m\) 变换而来,\(B_i\) 对应了 \(A_{p_i}\)。
拿出 \(A_1,A_2\),设它们在 \(B\) 中相差了 \(k\) 个位置。那么有 \(kd \equiv A_2-A_1 \bmod{m}\)。
\(kd\) 这个差在 \(B\) 中出现了 \(n-k\) 次。那么在 \(A\) 中呢?
Lemma:若 \(2n \leq m\),那么 \(kd\) 这个差在 \(A\) 中一定出现了 \(n-k\) 次。
由于 \(m\) 为质数,\(d<m\),那么有 \(\gcd(d,m)=1\)。
从 $A_{p_i} $ 到 \(A_{p_{i+1}}\),相当于在一个长度为 \(m\) 的环上前进了 \(d\) 格。如果 \(A\) 无限延伸下去,那么会形成长度为 \(m\) 的循环,每一轮循环内不重不漏地遍历了环上的每一个点。
对于 \(1 \leq i \leq n-k\),一定恰好存在一个 \(j\),使得 \(A_{p_j} \equiv A_{p_i}+kd \pmod{p}\)。
接下来证明对于 \(n-k<i\leq n\),不存在这样的 \(j\)。
如果 \(A_1\) 对应 \(B\) 的首,\(A_2\) 对应 \(B\) 的末,那么 \(k\) 可以取到最大值 \(n-1\)。
从 \(A_{p_1}\) 到 \(A_{p_n}\),需要在环上走 \(n-1\) 次。那么要走到 \(A_{p_n}+(n-1)d\),需要从 $ A_{p_1}$ 走 \(2n-2<m\) 次,没有完成循环,故这个点没有在 \(A\) 中出现过。
类似地,每一个 \(n-k<i\leq n\) 的 \(i\),\(A_{p_i}+kd\) 这个点都没有在 \(A\) 中出现过。
命题得证。
先考虑 \(2n\leq m\) 的情况。我们可以找出 \(A_2-A_1\) 这个差出现了多少次,从而求出 \(k\)。那么 \(d=(A_2-A_1) k^{-1}\)。
我们找出的 \(d\) 是必要的,而不是充分的。如果 \(A_i-d\) 在原序列中没有出现,那么在有解的情况下,\(A_i\) 就是数列开头。如果出现多个这样的 \(i\),那么无解。
如果 \(2n>m\),该怎么做?
我们在环上把 \(A\) 延伸下去,直至形成循环。新延伸的部分也是一个符合条件的等差数列。
我们取出这一部分,\(2n>m \Rightarrow 2(m-n)<m\),那么这一部分就能沿用上面的方法了。
int T,n,m,a[N],b[N],k;
int Mod(int x){
return (x>=m)?(x-m):(x);
}
ll QuickPow(ll x,ll y){
ll res=1;
while(y){
if(y&1) res=res*x%m;
x=x*x%m; y>>=1;
}
return res;
}
bool FindA(int x){
int p=lower_bound(a+1,a+n+1,x)-a;
return (p<=n&&a[p]==x);
}
bool FindB(int x){
int p=lower_bound(b+1,b+k+1,x)-b;
return (p<=k&&b[p]==x);
}
int Work(){
if(k==1) return 1;
int g=b[2]-b[1],cnt=1;
for(int i=2;i<=k;i++)
cnt+=FindB(Mod(b[i]+g));
return 1ll*QuickPow(k-cnt,m-2)*g%m;
}
void Solve(){
read(m),read(n);
for(int i=1;i<=n;i++) read(a[i]);
if(n==m) return puts("0 1"),void();
sort(a+1,a+n+1); k=0;
if(2*n>m){
for(int i=0;i<m;i++){
if(!FindA(i))
b[++k]=i;
}
}
else{
for(int i=1;i<=n;i++) b[i]=a[i];
k=n;
}
int d=Work(),s=-1;
for(int i=1;i<=n;i++){
int x=a[i],c=0;
if(!FindA(Mod(x-d+m))){
if(s==-1) s=a[i];
else return puts("-1"),void();
}
}
if(s==-1) puts("-1");
else printf("%d %d\n",s,d);
}

浙公网安备 33010602011771号