题目链接
题目解法
有旋转相同的题首先考虑置换
考虑
B
u
r
n
s
i
d
e
Burnside
Burnside 引理,需要求出不动点的个数
考虑一个点
x
x
x,每次往后跳
k
k
k 个(即旋转
k
k
k ),跳回
x
x
x 需要至少跳
t
t
t 次
可得
x
+
k
t
≡
x
(
m
o
d
n
)
x+kt\equiv x(mod\;n)
x+kt≡x(modn)
则
t
t
t 的最小值为
n
d
\frac{n}{d}
dn,其中
d
=
(
n
,
k
)
d=(n,k)
d=(n,k)
所以说当前置换环上有
t
t
t 即
n
d
\frac{n}{d}
dn 个点
因为每个点能到的点的形式均为
x
+
t
k
x+tk
x+tk 即
x
+
t
′
d
x+t'd
x+t′d
这样的点有
n
d
\frac{n}{d}
dn 个
因为每个点都不相同,所以每个点跳出的点相隔
d
d
d
根据
b
u
r
n
s
i
d
e
burnside
burnside 引理,不动点是
x
x
x 与
x
+
d
,
.
.
.
x+d,...
x+d,... 颜色都相同的点
所以只要考虑
x
,
x
+
1
,
.
.
.
,
x
+
d
−
1
x,x+1,...,x+d-1
x,x+1,...,x+d−1,且
x
x
x 不等于
x
+
d
−
1
x+d-1
x+d−1 的颜色的方案数
令
d
p
i
,
j
dp_{i,j}
dpi,j 表示当前
i
i
i 点的颜色为
j
j
j 的方案数
由于是一个环,所以需要固定
x
x
x 的颜色
因为
n
n
n 很大,所以需要矩阵乘法优化
d
p
dp
dp
且不能枚举每个
k
k
k,考虑枚举
d
d
d
那么需要知道
(
k
d
,
n
d
)
=
1
(\frac{k}{d},\frac{n}{d})=1
(dk,dn)=1 的
k
k
k 的个数,即为
ϕ
(
n
d
)
\phi(\frac{n}{d})
ϕ(dn)
时间复杂度
O
(
1600
m
4
l
o
g
n
)
O(1600m^4log\;n)
O(1600m4logn),其中
1600
1600
1600 为
i
n
t
int
int 范围内整数的最多因数个数
时间不够
考虑把
d
p
dp
dp 状态扩充为 3 维,再记录一维第一个点的颜色,矩乘的时间仍是
O
(
m
3
l
o
g
n
)
O(m^3log\;n)
O(m3logn),但可以减少枚举第一个点颜色的
m
m
m
时间复杂度
O
(
1600
m
3
l
o
g
n
)
O(1600m^3log\;n)
O(1600m3logn)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int M(15),P(9973);
struct Matrix{
int n,m,a[M][M];
}Bas,f;
Matrix operator *(const Matrix A,const Matrix B){
Matrix C;C.n=A.n,C.m=B.m;
memset(C.a,0,sizeof(C.a));
for(int i=1;i<=C.n;i++) for(int j=1;j<=C.m;j++) for(int k=1;k<=A.m;k++) C.a[i][j]=(C.a[i][j]+(LL)A.a[i][k]*B.a[k][j])%P;
return C;
}
int n,m,k;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
int getphi(int x){
int res=x;
for(int i=2;i*i<=x;i++)
if(x%i==0){
while(x%i==0) x/=i;
res=res/i*(i-1);
}
if(x>1) res=res/x*(x-1);
return res;
}
int solve(int d){
int totk=getphi(n/d);
int res=0;
// cout<<d<<' '<<totk<<'\n';
memset(f.a,0,sizeof(f.a));
f.n=m,f.m=m;
for(int i=1;i<=m;i++) f.a[i][i]=1;
Matrix mul=Bas;
int tn=d-1;
for(;tn;tn>>=1){
if(tn&1) f=f*mul;
mul=mul*mul;
}
for(int i=1;i<=m;i++)
// cout<<f.a[1][1]<<' '<<f.a[1][2]<<' '<<f.a[1][3]<<'\n';
for(int j=1;j<=m;j++) if(Bas.a[i][j]) (res+=f.a[i][j])%=P;
// cout<<res<<'\n';
return (LL)res*totk%P;
}
int qmi(int a,int b,int p){
int res=1;
for(;b;b>>=1){
if(b&1) res=(LL)res*a%P;
a=(LL)a*a%p;
}
return res;
}
void work(){
n=read(),m=read(),k=read();
Bas.n=m,Bas.m=m;
for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) Bas.a[i][j]=1;
for(int i=1,a,b;i<=k;i++) a=read(),b=read(),Bas.a[a][b]=Bas.a[b][a]=0;
int ans=0;
for(int i=1;i*i<=n;i++)
if(n%i==0){
ans=(ans+solve(i))%P;
if(i*i!=n) ans=(ans+solve(n/i))%P;
}
// cout<<ans<<'\n';
printf("%d\n",(LL)ans*qmi(n,P-2,P)%P);
}
int main(){
int T=read();
while(T--) work();
return 0;
}
/*
f[i][j]+=f[i-1][k]
*/