分析:
做过hdu2865之后就不虚了
n个珠子的手镯,n种置换,每个置换的轮换个数
gcd(i,n)
g
c
d
(
i
,
n
)
(比较基础的东西)
对于一个置换(转动
i
i
个珠子),我们要保证连续的长度不能出现矛盾
即给一个长度为
gcd(i,n)
g
c
d
(
i
,
n
)
的环上色,保证不出现矛盾
dp解决:
设计状态:
f[i][j]
f
[
i
]
[
j
]
表示第
i
i
位是第种珠子的方案数
如果是一个序列的状态,那么转移比较简单:
f[i][j]=∑mi=1f[i−1][k](j,k不存在矛盾)
f
[
i
]
[
j
]
=
∑
i
=
1
m
f
[
i
−
1
]
[
k
]
(
j
,
k
不
存
在
矛
盾
)
环形问题我们可以用矩阵来完成,不过需要把状态改一改:
f[i][j]
f
[
i
]
[
j
]
表示队首是第
i
i
种珠子,队尾是第种珠子的方案数
最后统计答案的时候,直接忽略
(i,j)
(
i
,
j
)
存在矛盾的情况
ans=1n∑ni=1f(gcd(i,n)) a n s = 1 n ∑ i = 1 n f ( g c d ( i , n ) )
上奇技淫巧:
ans=1n∑d|nphi(nd)f(d)
a
n
s
=
1
n
∑
d
|
n
p
h
i
(
n
d
)
f
(
d
)
tip
注意f(1)的计算:
int ans=0;
for (int i=1;i<=m;i++) if (mp[i][i]) ans++;
return ans;
被卡常数,真心不想改了
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int N=1000000;
const int p=9973;
int n,m,k,sshu[N],tot=0,phi[N];
bool no[N];
struct node{
int H[12][12];
node operator *(const node &a) const
{
node ans;
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
{
ans.H[i][j]=0;
for (int k=1;k<=m;k++)
ans.H[i][j]=(ans.H[i][j]+H[i][k]%p*a.H[k][j]%p)%p;
}
return ans;
}
void clear()
{
for (int i=1;i<=m;i++) for (int j=1;j<=m;j++) H[i][j]=1;
}
node KSM(ll b)
{
node ans=(*this),a=(*this);
b--;
while (b)
{
if (b&1) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
};
node H,A;
void prepare()
{
phi[1]=1;
for (int i=2;i<N;i++)
{
if (!no[i]) {
sshu[++tot]=i;
phi[i]=i-1;
}
for (int j=1;j<=tot&&sshu[j]*i<N;j++)
{
no[sshu[j]*i]=1;
if (i%sshu[j]==0) {
phi[i*sshu[j]]=phi[i]*sshu[j];
break;
}
phi[i*sshu[j]]=phi[i]*phi[sshu[j]];
}
}
}
int KSM(int a,int b)
{
a%=p;
int t=1;
while (b)
{
if (b&1) t=(t*a)%p;
b>>=1;
a=(a*a)%p;
}
return t;
}
int Phi(int x)
{
if (x<N) return phi[x]%p;
ll ans=x;
for (int i=1;i<=tot&&sshu[i]*sshu[i]<=x;i++) if (x%sshu[i]==0)
{
ans=(ll)ans/sshu[i]*(sshu[i]-1);
while (x%sshu[i]==0) x/=sshu[i];
}
if (x>1) ans=(ll)ans/x*(x-1);
return ans;
}
int F(int x)
{
if (x==1)
{
int ans=0;
for (int i=1;i<=m;i++) if (H.H[i][i]) ans++;
return ans;
}
A=H.KSM(x-1);
int ans=0;
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
if (H.H[i][j]) ans=(ans+A.H[i][j])%p;
return ans;
}
int main()
{
prepare();
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&n,&m,&k);
H.clear();
for (int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
H.H[x][y]=H.H[y][x]=0;
}
int ans=0;
for (int i=1;i*i<=n;i++) if (n%i==0)
{
int x=i,y=n/i;
ans=(ans+Phi(y)%p*F(x)%p)%p;
if (x!=y) ans=(ans+Phi(x)%p*F(y)%p)%p;
}
ans=(ans*KSM(n,p-2)%p)%p;
printf("%d\n",ans);
}
return 0;
}