HDU 3923 Invoker

题目大意 :用n种颜色去给圆上正m边形顶点涂色,共有多少种涂色方法(能通过旋转或对称得到的认为是相同的涂色方法)
解题思路:看到这种旋转,对称置换处理的方法数首先考虑ploya定理,即通过每种置换方式保持使着色相同的着色数之和,再求平均。
对于正n边形只考虑旋转,对称就行,其中旋转有n中,对称有n中,再考虑每种置换能保持多少种着色不变。
对于旋转,gcd(n,i) i:0~n-1 代表循环节数,即置换可分解的因子数(请参考组合数学相关知识),着色数ans1 = 颜色数^gcd(n,i)。
对于对称,若n为奇数 循环节数=(n+1)/2   若n为偶数 分对角线过顶点(循环节数=(n-2/2+2))、不过顶点(n/2),着色数相应算出ans2。
最后结果  ans = (ans1+ans2)/(2*n)。
最后注意一点计算过程中可能就超出最大表示范围,最后除以2*n取模就不对了,这里wrong了几次,最后参考网上改了下<pre name="code" class="cpp">(ans*pow(2*m,M-2))%M,有待证明。
 


#include <iostream>
#include <cstdio>
using namespace std;

#define LL long long
#define M  1000000007
int n,m;
LL pow(LL a,int b){  //a^b
	LL ans = 1;
	while(b>0){
		if(b&1) ans = (ans*a)%M;
		a = (a*a)%M;
		b>>=1;
	}
	return ans;
}
int gcd(int a,int b){
	if(b==0) return a;
	return gcd(b,a%b);
}
int main(){
	int T;
	cin >> T;
	int c = 1;
	while(T--){
		cin >> n >> m;
		LL ans = 0;
		//旋转置换 
		for(int i=0;i<m;i++){
			ans = (ans+ pow(n,gcd(m,i)))%M;
		}
		//对称置换  分奇偶 
		if(m&1){
			ans = (ans+m*pow(n,(m+1)/2))%M;
		}
		else{
			ans = (ans+m/2*pow(n,m/2)*(n+1))%M;
		}
	//	 printf("Case #%d: %I64d\n",c++,ans/2/m);
		printf("Case #%d: %I64d\n",c++,(ans*pow(2*m,M-2))%M);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值