有个质数(P),然后有个图,点编号为(1dots P-1)。给出数字(a,b)。
对于(iin [1,P-1]),连双向边((i,aimod P),(i,bimod P))。
构造一条哈密顿回路。
(Ple 10^5)
设(n)为(a)在模意义下的阶,记(H={a^i|iin[0,n)})。记最小的满足(b^min H)的(m)为(m)。
首先有解的必要条件是任意数都能表示成(a^ib^j)。可以证明,如果有这样的表示方法,那一定存在(iin[0,n),jin[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_2equiv 0pmod 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
");
return 0;
}
if (n==1 && m==1){
printf("Yes
1 1
");
return 0;
}
if (n&1)
swap(a,b),getnm(a,b);
invb=qpow(b);
printf("Yes
");
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
");
return 0;
}