Count the Tetris

Count the Tetris

題解

這是一道很經典的Burnside的題目。

我們很容易發現對於一個長度爲n的環,需要一個置換中的不動點滿足它的所有循環中的點顏色相同,那麼在旋轉i次的置換中,循環共有\left(n,i \right )個。由於後面的循環都是重複的我們只需計算\left(n,i \right )這段的染色方案即可。

看到題目限制,如果直接統計的話肯定會T,所以需要用矩陣乘法來進行統計。

考慮n特別大的範圍,還需要歐拉函數對其進行優化,枚舉置換的循環節個數i,與其等價的置換羣共有\varphi\left(\frac{n}{i} \right )個,需要再將其乘上去,而我們只需要枚舉n的因數來進行計算。

源碼

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define MAXN 40010
typedef long long LL;
//#define int LL
typedef pair<int,int> pii;
const int mo=9973;
#define gc() getchar()
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=gc();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int prime[MAXN],cntp,n,m,k;
bool oula[MAXN];
struct Matrix{
	int c[15][15];
	//Matrix(){memset(c,0,sizeof(0));}
	/*Martix operator * (const Martix &b)const{
		Martix res;
		for(int i=0;i<m;i++)
			for(int k=0;k<m;k++)
				if(c[i][k])
					for(int j=0;j<m;j++)
						(res.c[i][j]+=c[i][k]*b.c[k][j]%mo)%mo;
		return res;
	}*/
}mat;
Matrix mult(Matrix ta,Matrix tb){
	Matrix tc;memset(tc.c,0,sizeof(tc.c));
	for(int i=0;i<m;i++)
		for(int k=0;k<m;k++)
			if(ta.c[i][k])
				for(int j=0;j<m;j++)
					(tc.c[i][j]+=ta.c[i][k]*tb.c[k][j])%=mo;
	return tc;
}
Matrix Matpow(Matrix a,int s){
	Matrix t;memset(t.c,0,sizeof(t.c));
	for(int i=0;i<m;i++)t.c[i][i]=1;
	while(s){
		if(s&1)t=mult(t,a);
		a=mult(a,a);s>>=1;
	}
	return t;
}
int qkpow(int a,int s){
	int t=1;a%=mo;
	while(s){
		if(s&1)t=t*a%mo;
		a=a*a%mo;s>>=1;
	}
	return t;
}
void init(){
	for(int i=2;i<=4e4;i++){
		if(oula[i])continue;
		prime[cntp++]=i;
		for(int j=i*i;j<=4e4;j+=i)
			oula[j]=1;
	}
}
int euler(int cur){
	int ans=cur,x=cur;
	for(int i=0;i<cntp&&prime[i]*prime[i]<=cur;i++)
		if(x%prime[i]==0){
			ans=ans/prime[i]*(prime[i]-1);
			while(x%prime[i]==0)x/=prime[i];
		}
	if(x>1)ans=ans/x*(x-1);
	return ans%mo;
}
int cal(int len){
	int res=0;Matrix t=Matpow(mat,len);
	for(int i=0;i<m;i++)(res+=t.c[i][i])%=mo;
	return res;
}
int Polya(){
	int ans=0;
	for(int i=1;i*i<=n;i++){
		if(n%i)continue;
		if(i*i==n)(ans+=cal(i)*euler(i))%=mo;
		else (ans+=cal(i)*euler(n/i)+cal(n/i)*euler(i))%=mo;
		//printf("%d:%d\n",i,ans);
	}
	return ans*qkpow(n,mo-2)%mo;
}
signed main(){
	int T;read(T);init();
	while(T--){
		read(n);read(m);read(k);
		for(int i=0;i<m;i++)
			for(int j=0;j<m;j++)
				mat.c[i][j]=1;
		for(int i=1;i<=k;i++){
			int u,v;read(u);read(v);
			mat.c[u-1][v-1]=mat.c[v-1][u-1]=0;
		}
		printf("%d\n",Polya());
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章