CF763C Timofey and remoduling

CF763C Timofey and remoduling

Description

CF763C Timofey and remoduling

给出 \(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);
}
posted @ 2025-02-15 22:19  XP3301_Pipi  阅读(70)  评论(0)    收藏  举报
Title