BZOJ1004 [HNOI2008]Cards(Polya计数)

枚举每个置换,求在每个置换下着色不变的方法数,先求出每个循环的大小,再动态规划求得使用给定的颜色时对应的方法数。

dp[i][j][k]表示处理到当前圈时R,B,G使用量为i,j,k时的方法数,背包思想。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<utility>
using namespace std;
typedef long long LL;
const int N = 68, INF = 0x3F3F3F3F;
#define MS(a, num) memset(a, num, sizeof(a))
#define PB(A) push_back(A)
#define FOR(i, n) for(int i = 0; i < n; i++)
int r, g, b, m, p, n;
int dis[N][N];
bool vis[N];
LL dp[N][N][N];

LL Ext_gcd(LL a,LL b,LL &x,LL &y){//扩展欧几里得
   if(b==0) { x=1, y=0; return a; }
   LL ret= Ext_gcd(b,a%b,y,x);
   y-= a/b*x;
   return ret;
}
LL Inv(LL a,int m){   ///求逆元
   LL d,x,y,t= (LL)m;
   d= Ext_gcd(a,t,x,y);
   if(d==1) return (x%t+t)%t;
   return -1;
}

LL solve(){
    LL ans = 0;
    for(int x = 0; x < m; x++){
        memset(vis, 0, sizeof(vis));
        vector<int> v;
        for(int i = 1; i <= n; i++){
            if(!vis[i]){
                int cnt = 0;
                int tp = i;
                while(!vis[tp]){
                    cnt++;
                    vis[tp] = 1;
                    tp = dis[x][tp];
                }
                v.push_back(cnt);
            }
        }
        memset(dp, 0, sizeof(dp));
        dp[0][0][0] = 1;
        for(int t = 0; t < v.size(); t++){
            for(int i = r; i >= 0; i--){
                for(int j = b; j >= 0; j--){
                    for(int k = g; k >= 0; k--){
                        if(i == 0 && j == 0 && k == 0){
                            continue;
                        }
                        dp[i][j][k] = 0;
                        if(i >= v[t]){
                            dp[i][j][k] = (dp[i][j][k] + dp[i - v[t]][j][k]) % p;
                        }
                        if(j >= v[t]){
                            dp[i][j][k] = (dp[i][j][k] + dp[i][j - v[t]][k]) % p;
                        }
                        if(k >= v[t]){
                            dp[i][j][k] = (dp[i][j][k] + dp[i][j][k - v[t]]) % p;
                        }
                    }
                }
            }
        }
        ans = (ans + dp[r][b][g]) % p;
    }
    ans = ans * Inv(m, p) % p;
    return ans;
}
int main(){
    while(~scanf("%d %d %d %d %d", &r, &b, &g, &m, &p)){
        n = r + b + g;
        bool f = 1;
        for(int i = 0; i < m; i++){
            int cnt = 0;
            for(int j = 1; j <= n; j++){
                scanf("%d", &dis[i][j]);
                if(dis[i][j] == j){
                    cnt++;
                }
            }
            if(cnt == n){
                f = 0;
            }
        }
        if(f){
            for(int i = 1; i <= n; i++){
                dis[m][i] = i;
            }
            m++;
        }
        printf("%lld\n", solve());
    }
    return 0;
}

  

时间: 2024-10-18 00:16:27

BZOJ1004 [HNOI2008]Cards(Polya计数)的相关文章

BZOJ 1004: [HNOI2008]Cards Polya计数+DP

Polya计数+dp求满足对应循环的不动点有几个 1004: [HNOI2008]Cards Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2046  Solved: 1212 [Submit][Status][Discuss] Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,S

[BZOJ1004] [HNOI2008] Cards (Polya定理)

Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.Sun发现这个问题有点难度,决

BZOJ1004 [HNOI2008]Cards

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! 题目链接:BZOJ1004 正解:$Burnside$引理 解题报告: 经典$Burnside$引理题. 考虑一般的$Burnside$引理题都是直接求出一阶循环的个数,然后对于置换个数取平均数. 但是有颜色限制,所以我们不能直接算. 而因为一个洗牌方案相

[BZOJ1004] [HNOI2008]Cards解题报告(Burnside引理)

Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.Sun发现这个问题有点难度,决

BZOJ1004 [HNOI2008]Cards 【burnside定理 + 01背包】

题目链接 BZOJ1004 题解 burnside定理 在\(m\)个置换下本质不同的染色方案数,等于每种置换下不变的方案数的平均数 记\(L\)为本质不同的染色方案数,\(m\)为置换数,\(f(i)\)为置换\(i\)下不变的方案数,那么 \[L = \frac{1}{m}\sum\limits_{i = 1}^{m} f(i)\] 在一个置换下一个方案不变,当且仅当该置换的任意一个循环节内部颜色相同 记循环节个数为\(c_i\),色数为\(k\)且不限使用,那么该置换下不变的方案数为 \[

[BZOJ1004][HNOI2008]Cards 群论+置换群+DP

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1004 首先贴几个群论相关定义和引理. 群:G是一个集合,*是定义在这个集合上的一个运算. 如果满足以下性质,那么(G, *)是一个群. 1)封闭性,对于任意 a, b 属于 G, a * b 属于 G 2)结合律, a * b * c = a * (b * c) 3)单位元,在 G 中存在一个单位元 e ,使得对于 G 中任意的 a , a * e = e * a = a 4)逆元, 对

[bzoj1004][HNOI2008][Cards] (置换群+Burnside引理+动态规划)

Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.Sun发现这个问题有点难度,决

bzoj1004: [HNOI2008]Cards Burnside引理+01背包

三维01背包算出在每一个置换下不变的染色方案数,Burnside引理计算答案. PS:数据太水所以只算恒等置换也是可以过的. #include<bits/stdc++.h> using namespace std; int n,m,p,x,y,z; bool u[61]; int f[21][21][21],s[61],v[61]; int power(int u,int v){ int d=1; for(;v;v>>=1){ if(v&1) d=d*u%p; u=u*u%

bzoj1004: [HNOI2008]Cards(burnside引理+DP)

题目大意:3种颜色,每种染si个,有m个置换,求所有本质不同的染色方案数. 置换群的burnside引理,还有个Pólya过几天再看看... burnside引理:有m个置换k种颜色,所有本质不同的染色方案数就是每种置换的不变元素的个数的平均数. 求每种置换的不变元素的个数用背包解决.因为置换之后元素不变,所以对于每个循环节我们要染一个颜色,于是先处理出循环节作为背包中的"物体",然后一个三维背包解决.f[i][j][k]的i j k表示三种颜色分别还可以染多少次. 除m%p用费马小定