bzoj1004: [HNOI2008]Cards
2016-02-20 16:42
232 查看
题目链接
bzoj1004题意
Description
小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).Input
第一行输入 5 个整数:Sr,Sb,Sg,m,p(m<=60,m+1Output
不同染法除以P的余数Sample Input
1 1 1 2 72 3 1
3 1 2
Sample Output
2HINT
有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。100%数据满足 Max{Sr,Sb,Sg}<=20。
题解
Burnside定理:有m个置换k种颜色,所有本质不同的染色方案数就是每种置换的不变的染色方案的个数的平均数。对于一个置换找出所有循环节,将循环节染成相同颜色就是一种不变的染色方案。有颜色个数的限制就用背包dp。
要算平均数就又用乘法逆元,这题可以用扩展欧几里得,也可以用费马小定理。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #include<vector> using namespace std; int sa,sb,sc,m,p,n,a[70][70],f[70][70][70],s[70],v[70],ans; int dp(int x){ memset(v,0,sizeof(v)); memset(s,0,sizeof(s)); memset(f,0,sizeof(f)); int cnt=0; for(int i=1;i<=n;i++) if(!v[i]){ v[i]=1; s[++cnt]=1; for(int p=i;!v[a[x][p]];p=a[x][p]) s[cnt]++,v[a[x][p]]=1; } f[0][0][0]=1; for(int i=1;i<=cnt;i++) for(int j=sa;j>=0;j--) for(int k=sb;k>=0;k--) for(int l=sc;l>=0;l--){ if(s[i]<=j) f[j][k][l]=(f[j][k][l]+f[j-s[i]][k][l])%p; if(s[i]<=k) f[j][k][l]=(f[j][k][l]+f[j][k-s[i]][l])%p; if(s[i]<=l) f[j][k][l]=(f[j][k][l]+f[j][k][l-s[i]])%p; } return f[sa][sb][sc]; } int power(int x,int y){ int tmp=1; for(;y;y>>=1,x=x*x%p) if(y&1) tmp=tmp*x%p; return tmp; } int main(){ scanf("%d%d%d%d%d",&sa,&sb,&sc,&m,&p); n=sa+sb+sc; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); m++; for(int i=1;i<=n;i++) a[m][i]=i; for(int i=1;i<=m;i++) ans=(ans+dp(i))%p; printf("%d",ans*power(m,p-2)%p); return 0; }
相关文章推荐
- 328. Odd Even Linked List
- 常用的加密算法介绍
- java多态学习
- erlang访问https地址
- BZOJ3084 : [Algorithmic Engagements 2011]The Shortest Period
- DP+树状数组优化-sort it-neu2016第一次月赛
- C/C++内存问题检查利器
- LeetCode 257. Binary Tree Paths 解题报告
- New Relic——手机应用app开发达人的福利立即就到啦!
- Android动画动画二
- Android动画属性一
- Android接收短信-createFromPdu
- QQ5.0 侧滑栏效果
- uva 10253
- [Python]list, tuple, dict的区别
- join()——化多线程并发执行为顺序执行
- BZOJ 4028: [HEOI2015]公约数数列 分块
- Javascript作用域和变量提升
- 自己设计MD风格侧滑栏
- linux进入救援模式的方法