码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1004 [HNOI2008]Cards

时间:2018-02-20 12:54:48      阅读:113      评论:0      收藏:0      [点我收藏+]

标签:iostream   cstring   ace   turn   return   main   ems   ide   name   

题解:burnside引理

DP出不动点的数目,用burnside引理算等价类

问题:不明白burnside引理的原理

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

int n,m,mm;
int Sr,Sb,Sg;
int tot;

int a[100];
int vis[100];
int b[100],nn;
int f[30][30][30];
void Calc(){
	nn=0;
	memset(vis,0,sizeof(vis));
	memset(f,0,sizeof(f));
	memset(b,0,sizeof(b));
	for(int i=1;i<=n;++i){
		if(vis[i])continue;
		++nn;
		int x=i;
		while(!vis[x]){
			vis[x]=1;b[nn]++;x=a[x];
		}
	}
//	for(int i=1;i<=nn;++i)cout<<b[i]<<‘ ‘;
//	cout<<endl;
	f[0][0][0]=1;
	for(int i=1;i<=nn;++i){
		for(int x=Sr;x>=0;--x){
			for(int y=Sb;y>=0;--y){
				for(int z=Sg;z>=0;--z){
					int t=b[i];
					if(x>=t)f[x][y][z]+=f[x-t][y][z];
					if(y>=t)f[x][y][z]+=f[x][y-t][z];
					if(z>=t)f[x][y][z]+=f[x][y][z-t];
					f[x][y][z]%=mm;
				}
			}
		}
	}
	tot=(tot+f[Sr][Sb][Sg])%mm;
}

int Ksm(int a,int p){
	int ret=1;
	for(;p;p>>=1,a=a*a%mm){
		if(p&1)ret=ret*a%mm;
	}
	return ret;
}

int main(){
	scanf("%d%d%d%d%d",&Sr,&Sb,&Sg,&m,&mm);
	n=Sr+Sb+Sg;
	for(int k=1;k<=m;++k){
		for(int i=1;i<=n;++i)scanf("%d",&a[i]);
		Calc();
	}
	m++;
	for(int i=1;i<=n;++i)a[i]=i;
	Calc();
	cout<<tot*Ksm(m,mm-2)%mm;
	return 0;
}

  

BZOJ 1004 [HNOI2008]Cards

标签:iostream   cstring   ace   turn   return   main   ems   ide   name   

原文地址:https://www.cnblogs.com/zzyer/p/8455006.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!