POJ 2154 Color Polya定理+欧拉函数优化

点击打开链接

Polya简介

题意:n个珠子围成一圈,有n种颜色,旋转后相同的视为同一种方案.
n<=1e9,P<=3e4,问不同的上色方案数并将结果余P. 


旋转后相同视为同一种,用Polya定理来计数
确定置换群,计算循环节个数,代入公式即可.


本题置换群为旋转1.2...n格,置换i的循环节个数为gcd(n,i)


由于n<=1e9 不能直接带入 把gcd相同的分为一类 对于 每一类n^d,求出有多少个i满足,gcd(n,i)=d -> gcd(n/d,i/d)=1 即欧拉函数(n/d) 



#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int N=2e5+20;
const int M=6e4;
int n,p;
int pri[N+20],vis[N+20];
void init()
{
	memset(vis,0,sizeof(vis));
	for(int i=2,j=0;i<=M;i++)
	{
		if(!vis[i])
		{
			pri[j++]=i;
			for(int j=i+i;j<=M;j+=i)
				vis[j]=1;
		}
	}
	
}
int phi(int n)
{
	int res=n;
	for(int i=0;pri[i]*pri[i]<=n;i++)
	{
		if(n%pri[i]==0)
		{
			res=res/pri[i]*(pri[i]-1);
			while(n%pri[i]==0)
				n/=pri[i];
		}
	}
	if(n>1)
		res=res/n*(n-1);
	return res;
}
int powmod(int n,int m,int p)
{
	int s=1;
	n%=p;
	while(m)
	{
		if(m&1)
			s=(s*n)%p;
		n=(n*n)%p;
		m>>=1;
	}
	return s;
}
int main()
{
	init();
	int t;
	cin>>t;
	while(t--)
	{
		scanf("%d%d",&n,&p);
		int ans=0;
		for(int d=1;d*d<=n;d++) 
		{
		 	if(n%d==0)
			{
				//×î´ó¹«Ô¼ÊýΪdʱ,gcd(n,i)=d,gcd(n/d,i/d)=1Âú×ãÌõ¼þµÄiÓÐphi[n/d]¸ö 
				int res=(phi(n/d)%p*powmod(n,d-1,p))%p;
				ans=(ans+res)%p;
				if(d*d==n)	continue;
				
				res=(phi(d)%p*powmod(n,n/d-1,p))%p;
				ans=(ans+res)%p;
			}
		}
		cout<


你可能感兴趣的:(Math)