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 <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
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<<ans<<endl;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值