zoukankan      html  css  js  c++  java
  • 项链(burnside)

    Description

    有一个长度为 (n) 的项链,首尾相接形成环,现在你要给每一个位置一个颜色 ([1,m]), 求所有不同的项链个数(可以通过旋转变成一样的称为相同)

    Solution

    根据 (burnside) 引理,答案为 (frac{1}{n}sum_{i=1}^{|G|}c1_i)
    也就是枚举所有的置换,求不动点个数之和
    置换一共有 (n) 种,分别为 (1,2...n)
    枚举旋转的长度 (i) ,那么循环节的大小为 (frac{n}{gcd(i,n)}) , 循环节个数为 (gcd(i,n))
    为什么?要使得 (k*i mod n=0) ,那么 (k*i) 的最小值就是 (lcm=frac{i*n}{gcd(i,n)}) ,所以 (k) 就等于 (frac{n}{gcd(i,n)})
    那么要使得这个点为不动点(旋转 (i) 之后一模一样),那么同一循环节里面的点必须颜色相同
    那么点的可以缩减为 (gcd(i,n))
    相当于问题转化为用 (m) 中颜色去覆盖 (x=gcd(i,n)) 个位置,我们设方案数为 (calc(x,m))

    转化为求 (sum_{i=1}^{n}calc(gcd(i,n),m))
    枚举 (gcd)
    答案就是 (sum_{i=1}^{n}calc(i)*phi[lfloorfrac{n}{i} floor])
    (calc) 函数可以用矩乘求出

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=1e7+10,mod=9973;
    int prime[N],num=0,phi[N],n,K,m;bool vis[N];
    inline void priwork(){
    	phi[1]=1;
    	for(int i=2,t;i<N;i++){
    		if(!vis[i])prime[++num]=i,phi[i]=i-1;
    		for(int j=1;j<=num && i*prime[j]<N;j++){
    			vis[t=i*prime[j]]=1;
    			if(i%prime[j])phi[t]=phi[i]*(prime[j]-1);
    			else {phi[t]=phi[i]*prime[j];break;}
    		}
    	}
    }
    inline int getphi(int x){
    	if(x<N)return phi[x];
    	int lim=sqrt(x),ret=x;
    	for(int i=1;i<=num && prime[i]<=lim;i++){
    		if(x%prime[i]==0){
    			ret=ret/prime[i]*(prime[i]-1);
    			while(x%prime[i]==0)x/=prime[i];
    		}
    	}
    	if(x>1)ret=ret/x*(x-1);
    	return ret;
    }
    struct mat{
    	int a[10][10];
    	inline void init(){memset(a,0,sizeof(a));}
    	inline mat operator *(const mat &p)const{
    		mat ret;
    		for(int i=0;i<m;i++)
    			for(int j=0;j<m;j++){
    				ret.a[i][j]=0;
    				for(int k=0;k<m;k++)
    					if(a[i][k] && p.a[k][j])
    						ret.a[i][j]=(ret.a[i][j]+a[i][k]*p.a[k][j])%mod;
    			}
    		return ret;
    	}
    }S,T;
    inline int calc(int x){
    	S.init();
    	for(int i=0;i<m;i++)S.a[i][i]=1;
    	mat D=T;x--;
    	while(x){
    		if(x&1)S=S*D;
    		D=D*D;x>>=1;
    	}
    	int ret=0;
    	for(int i=0;i<m;i++)
    		for(int j=0;j<m;j++)ret=(ret+S.a[i][j]*T.a[i][j])%mod;
    	return ret;
    }
    inline int qm(int x,int k){
    	int sum=1;if(x>=mod)x%=mod;
    	while(k){
    		if(k&1)sum=sum*x%mod;
    		x=x*x%mod;k>>=1;
    	}
    	return sum;
    }
    inline void work(){
    	int x,y;
    	cin>>n>>m>>K;
    	T.init();
    	for(int i=0;i<m;i++)for(int j=0;j<m;j++)T.a[i][j]=1;
    	for(int i=1;i<=K;i++){
    		gi(x);gi(y);x--;y--;
    		T.a[x][y]=T.a[y][x]=0;
    	}
    	int lim=sqrt(n),ans=0;
    	for(int i=1;i<=lim;i++){
    		if(n%i)continue;
    	   ans=(ans+1ll*calc(i)*getphi(n/i))%mod;
    		if(i*i!=n)ans=(ans+1ll*calc(n/i)*getphi(i))%mod;
    	}
    	ans=ans*qm(n,mod-2)%mod;
    	cout<<ans<<endl;
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      priwork();
      int T;cin>>T;
      while(T--)work();
      return 0;
    }
    
    
  • 相关阅读:
    生成前N个自然数随机置换的3个程序
    网络流媒体协议之——RTSP协议
    海思屏幕HAL代码解析
    事件路由
    hi3559v100 sdk中双系统AMP架构的初步了解
    LCD RGB 控制技术 时钟篇(下)【转】
    liteos C++支持(十七)
    liteos MMU(十八)
    APP接口做什么?
    APP如何进行通信的
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9085718.html
Copyright © 2011-2022 走看看