【Polya计数+背包】HDU6360 Kaleidoscope

【题目】
原题地址
一个正十二面体,用 n n n种颜色涂色,第 i i i种颜色至少要用 c i c_i ci次,求方案数。

【解题思路】
polya好题。

首先写出所有置换。

不动: 1 1 1
对棱中点连线旋转: 30 ∗ 1 2 = 15 \frac {30*1} 2 =15 2301=15
对顶点连线旋转: 20 ∗ 2 2 = 20 \frac {20*2} 2=20 2202=20
对面中点连线旋转: 12 ∗ 4 2 = 24 \frac {12*4} 2 = 24 2124=24

接下来我们需要证明这是一个置换群。
然而这个东西实在是太难搞了,我们只能YY一下,它就是一个群。

那么现在四个置换群循环节长度分别为 1 , 2 , 3 , 5 1,2,3,5 1,2,3,5,对应循环节个数 60 , 30 , 20 , 12 60,30,20,12 60,30,20,12
也就是说现在我们要计算的就是染完每种循环的方案数,这个用一个背包就可以解决。
f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i种颜色,染了 j j j个循环节的方案数,那么我们有:
f [ i ] [ j ] = ∑ k = c i j f [ i − 1 ] [ j − k ] × ( j k ) f[i][j]=\sum_{k=c_i}^j f[i-1][j-k]\times {j \choose k} f[i][j]=k=cijf[i1][jk]×(kj)

一个问题是模数不一定是素数,那最后除法除不尽。
我们可以将模数先乘以 60 60 60,这样计算除的结果一定是整除 60 60 60的,最后再将答案除以 60 60 60即可,需要使用快速乘。

【参考代码】

#include
using namespace std;

typedef long long LL;
typedef long double ldb;
const int N=65;
const ldb eps=1e-8;
int T,n,m;
int sum[5],c[N],d[]={1,2,3,5},num[]={1,15,20,24};
LL mod,ans,C[N][N],f[N];

void up(LL &x,LL y) {x+=y;if(x>=mod)x-=mod;}
LL upm(LL x) {return x>=mod?x-mod:x;}
LL mul(LL x,LL y) {return (x*y-(LL)(x/(ldb)mod*y+eps)*mod+mod)%mod;}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("HDU6360.in","r",stdin);
	freopen("HDU6360.out","w",stdout);
#endif
	scanf("%d",&T);
	while(T--)
	{
		memset(sum,0,sizeof(sum));ans=0;
		scanf("%d%d",&n,&m);mod=(LL)m*60;
		for(int i=0;i<=60;++i)
		{
			C[i][0]=C[i][i]=1;
			for(int j=1;jtn) continue;
			memset(f,0,sizeof(f));f[0]=1;
			for(int j=0;j

【总结】
我说它是一个群,它就是一个群。

你可能感兴趣的:(数论-Polya计数)