ARC118D Hamiltonian Cycle

有个质数\(P\),然后有个图,点编号为\(1\dots P-1\)。给出数字\(a,b\)

对于\(i\in [1,P-1]\),连双向边\((i,ai\mod P),(i,bi\mod P)\)

构造一条哈密顿回路。

\(P\le 10^5\)


\(n\)\(a\)在模意义下的阶,记\(H=\{a^i|i\in[0,n)\}\)。记最小的满足\(b^m\in H\)\(m\)\(m\)

首先有解的必要条件是任意数都能表示成\(a^ib^j\)。可以证明,如果有这样的表示方法,那一定存在\(i\in[0,n),j\in[0,m)\)的表示,且唯一。

存在性显然。唯一性:如果存在\(a^{i_1}b^{j_1}=a^{i_2}b^{j_2}\),那么有\(a^{i_1-i_2}=b^{j_1-j_2}\),可得\(b^{j_1-j_2}\in H\),根据\(m\)的定义可得\(j_1-j_2\equiv 0\pmod m\)

这也说明了能被表示的数的个数是\(nm\)。因此\(P-1=nm\)是有解的必要条件。然后构造使得它为充分条件:

可以看做一个二维的网格(\(n\)\(m\)列),其中最下面一行往下走可以到最上面一行同一列,最右边一列往右走可以到左边某一列但不一定同行(因为这样比较阴间所以尝试不走这样的边将其构造得出)。

官方题解中的Method3(可以处理\(n,m>1\)时的所有情况):

如果\(n\)为偶数,可以直接蛇形构造,最后在点\((n-1,0)\)跳到\((0,0)\)

如果\(n\)为奇数,把\(a,b\)交换,可以证明交换后得到\(n'\)一定会是偶数。

证明即证\(a,b\)的阶至少有一个为偶数。

设原根为\(g\),则\(a,b\)可以分别表示为\(g^A,g^B\),阶分别为\(\frac{P-1}{A},\frac{P-1}{B}\)。如果阶都是奇数,那么\(A,B\)都是偶数,当\(P\)为奇素数时,能表示的值\(g^x\)一定满足\(x\)是偶数,于是\(x\)为奇数的就表示不出来,与\(a^ib^j\)可以表示所有数矛盾。


using namespace std;
#include <bits/stdc++.h>
#define N 100005
#define ll long long
int P,a,b,invb;
ll qpow(ll x,ll y=P-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%P)
		if (y&1)
			r=r*x%P;
	return r;
}
bool vis[N];
int n,m;
void getnm(int a,int b){
	memset(vis,0,sizeof(bool)*P);
	n=0;
	for (int x=1;!vis[x];x=(ll)x*a%P)
		vis[x]=1,++n;
	m=1;
	for (int x=b;!vis[x];x=(ll)x*b%P)
		++m;
}
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d%d%d",&P,&a,&b);
	getnm(a,b);
	if (n*m<P-1){
		printf("No\n");
		return 0;
	}
	if (n==1 && m==1){
		printf("Yes\n1 1\n");
		return 0;	
	}
	if (n&1)
		swap(a,b),getnm(a,b);
	invb=qpow(b);
	printf("Yes\n");
	int x=1;
	for (int i=0;i<n;i+=2){
		printf("%d ",x);
		for (int j=1;j<m;++j){
			x=(ll)x*b%P;
			printf("%d ",x);
		}
		x=(ll)x*a%P;
		printf("%d ",x);
		for (int j=m-2;j>=0;--j){
			x=(ll)x*invb%P;
			printf("%d ",x);
		}
		x=(ll)x*a%P;
	}
	printf("1\n");
	return 0;
}
posted @ 2021-05-11 21:39  jz_597  阅读(198)  评论(0编辑  收藏  举报