題意:用m種不同顏色的珠子連成一條長爲n的項鍊,其中,有k對珠子不能相鄰,問總共有多少種(mod 9973)n<10^9,m<=10
題解:組合計數也就burning和polya了,這題用的是Burning Side。
考慮在一種置換f下的穩定核方法,由於只有旋轉對稱,如果是旋轉k個珠子,那麼穩定核的循環節也就是gcd(n,k)=r,枚舉k的話是不現實的,那麼只有枚舉r,即n的所有約數。gcd(n,k)=r,即gcd(n/r,k/r)=1,也就是與n/r互質的數的個數(歐拉函數)就是循環節爲r的置換個數。
對循環節爲r的情況,需要考慮循環節內部珠子的排列,使它們滿足題目要求,還要考慮第一個珠子與最後一個珠子是否滿足要求(最後一個珠子的下一個珠子也是下一輪的第一個珠子),由於珠子種類只有10,可以用鄰接矩陣map[i][j]表示i,j兩種珠子是否能相鄰,如果能,map[i][j]=1,反之,map[i][j]=0,這樣的話,離散數學老師應該說過,如果用0,1矩陣A來表示無向圖的連通情況的話,A^k代表的就是一個點經過k條路後能到達的地方的方法數。
因此,對於循環節爲r的情況,A^r就是任意點經過r條路能到達的地方,與之對應的map[i][i]就是一個珠子經過可行路徑轉了r條路徑又回到自己的種數,其實,就是前面說的滿足題意的排列數,矩陣乘法可以分治加個速,對於n的約數隨便求一下,這道題就出來了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int mr=100000;
const LL mod=9973;
bool notp[mr];
int pr[mr],fac[102],num[102];
int pn,top,n,m;
LL ans;
struct MAT
{
LL bas[13][13];
void init()
{
memset(bas,0,sizeof(bas));
}
} mat[50];
MAT mul(MAT a,MAT b)
{
MAT c;
c.init();
for(int i=1; i<=m; i++)
for(int k=1; k<=m; k++)
{
if(a.bas[i][k])
{
for(int j=1; j<=m; j++)
{
c.bas[i][j]+=a.bas[i][k]*b.bas[k][j];
if(c.bas[i][j]>=mod)
c.bas[i][j]%=mod;
}
}
}
return c;
}
void getpri()//篩素數
{
pn=0;
memset(notp,0,sizeof(notp));
for(int i=2; i<mr; i++)
{
if(!notp[i])
{
pr[pn++]=i;
}
for(int j=0; j<pn && i*pr[j]<mr; j++)
{
int k=i*pr[j];
notp[k]=1;
if(i%pr[j]==0)break;
}
}
}
void divn()
{
int nn=n;
top=0;
int lim=(int)sqrt((double(nn)))+1;
for(int i=0; pr[i]<=lim; i++)
{
if(nn%pr[i]==0)
{
fac[top]=pr[i];
num[top]=0;
while(nn%pr[i]==0)
num[top]++,nn/=pr[i];
top++;
}
}
if(nn>1)
fac[top]=nn,num[top++]=1;
}
int phi(int x)
{
int i, res=x;
for (i=0;pr[i]<(int)sqrt((double)x)+1;i++)
if(x%pr[i]==0)
{
res=res/pr[i]*(pr[i]-1);
while(x%pr[i]==0)x/=pr[i];
}
if(x>1)res=res/x*(x-1);
return res;
}
void solve(int r)
{
int res=phi(n/r);
MAT mt;
mt.init();
for(int i=1;i<=m;i++)
mt.bas[i][i]=1;
for(int i=1,tp=r;tp;i++,tp>>=1)
if(tp&1)mt=mul(mt,mat[i]);
for(int i=1;i<=m;i++)
{
ans+=mt.bas[i][i]*res;
if(ans>=mod)ans%=mod;
}
}
void dfs(int id,int sum)
{
if(id==top)
{
solve(sum);
return;
}
else
{
dfs(id+1,sum);
for(int ct=0; ct<num[id]; ct++)
dfs(id+1,sum=sum*fac[id]);
}
}
void init()
{
for(int i=2; i<50; i++)
mat[i]=mul(mat[i-1],mat[i-1]);
}
int Egcd (int a,int b, int &x, int &y)
{
if (b==0)
{
x=1,y=0;
return a;
}
LL d, tp;
d = Egcd (b, a%b, x, y);
tp = x;
x = y;
y = tp - a/b*y;
return d;
}
int getni()
{
int x,y;
Egcd(n,mod,x,y);
return (x%mod+mod)%mod;
}
int main()
{
getpri();
int T;
for(scanf("%d",&T); T; T--)
{
int k;
scanf("%d%d%d",&n,&m,&k);
ans=0;
for(int i=1; i<=m; i++)
for(int j=1; j<=m; j++)
mat[1].bas[i][j]=1;
for(int a,b,i=0; i<k; i++)
{
scanf("%d%d",&a,&b);
mat[1].bas[a][b]=mat[1].bas[b][a]=0;
}
init();
divn();
dfs(0,1);
printf("%d\n",ans*getni()%mod);
}
return 0;
}