zoukankan      html  css  js  c++  java
  • 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
    ", solve());
        }
        return 0;
    }
    

      

  • 相关阅读:
    LruCache 原理
    线程间通信, 进程间通信
    安卓 权限 规则
    android 捕获所有异常 未捕获的异常
    serializable parcelable
    android intent 传递 二进制数据
    apk安装 卸载 原理
    ARGB 8888 内存大小
    dalvik 基于 jvm 的改进
    查看 MySQL 数据库中每个表占用的空间大小
  • 原文地址:https://www.cnblogs.com/IMGavin/p/5863334.html
Copyright © 2011-2022 走看看