【HNOI2008】Cards BZOJ 1004

Description

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

Input

第一行输入 5 个整数:Sr,Sb,Sg,m,p(m<=60,m+1<p<100)。n=Sr+Sb+Sg。接下来 m 行,每行描述
一种洗牌法,每行有 n 个用空格隔开的整数 X1X2...Xn,恰为 1 到 n 的一个排列,表示使用这种洗牌法,
第 i位变为原来的 Xi位的牌。输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代替,且对每种
洗牌法,都存在一种洗牌法使得能回到原状态。

Output

不同染法除以P的余数

Sample Input

1 1 1 2 7
2 3 1
3 1 2

Sample Output

2

HINT

有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。

100%数据满足 Max{Sr,Sb,Sg}<=20。

思路

嘛~首先可以看到是组合数学的题目。之后就想大概是个什么模型。

看到在一个排列中元素可以交换,就想到了置换群,Polya计数法。

那么就是有这么多给你的置换方法,求本质上不同的排列有多少。我们将每一个置换群分解,找出置换的循环节:

比如置换1 4 3 5 2可以分解为(1)(2 4 5)(3)这三个循环节。

由polya计数法得:ans=所有置换中本质相同的方案的平均数。

看到100%数据满足 Max{Sr,Sb,Sg}<=20可以用dp做。

用f[i][j][k]表示用了i个红色,j个绿色,k个蓝色的方案数,则f[i][j][k]=f[i-size][j][k]+f[i][j-size][k]+f[i][j][k-size](size是当前循环节的大小)

最后不要忘记加上(1 2 3 ....n)这个循环,这个可以直接算出有N!/(sr!*sg!*sb!)

然后除以m+1,p为质数,用逆元算。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <queue>
 9 #include <stack>
10 #include <map>
11 #include <set>
12 #include <list>
13 #include <vector>
14 #include <ctime>
15 #include <functional>
16 #define pritnf printf
17 #define scafn scanf
18 #define For(i,j,k) for(int i=(j);i<=(k);(i)++)
19 #define Clear(a) memset(a,0,sizeof(a))
20 using namespace std;
21 typedef long long LL;
22 typedef unsigned int Uint;
23 const int INF=0x7fffffff;
24 //==============struct declaration==============
25
26 //==============var declaration=================
27 const int MAXN=30;
28 int sr,sb,sg,n,m,p,MOD,cnt=0;
29 int ans=0;
30 int tran[MAXN*5];
31 int f[MAXN][MAXN][MAXN];
32 bool vis[MAXN*5];
33 //==============function declaration============
34 int quickpow(int a,int Exp);
35 int inv(int a){return quickpow(a,MOD-2);}
36 int fact(int x){int ans=1;for(int i=1;i<=x;i++) ans=(ans*i)%MOD;return ans;}
37 //==============main code=======================
38 int main()
39 {
40 //#define FILE__
41 #ifdef FILE__
42   freopen("input.txt","r",stdin);
43   freopen("output.txt","w",stdout);
44 #endif
45   scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&MOD);n=sr+sb+sg;
46   for(int i=1;i<=m;i++){
47     for(int j=1;j<=n;j++)
48       scanf("%d",tran+j);
49     memset(vis,false,sizeof(vis));memset(f,0,sizeof(f));
50     f[0][0][0]=1;cnt=0;
51     for(int p=1;p<=n;p++){
52       if (vis[p]) continue;
53       cnt++;
54       int siz=0,x=p;
55       while (!vis[x]){
56         vis[x]=true;
57         x=tran[x];
58         siz++;
59       }//找出循环节
60       for(int i=sr;i>=0;i--)
61         for(int j=sb;j>=0;j--)
62           for(int k=sg;k>=0;k--){
63             if (i>=siz) f[i][j][k]+=f[i-siz][j][k];
64             if (j>=siz) f[i][j][k]+=f[i][j-siz][k];
65             if (k>=siz) f[i][j][k]+-f[i][j][k-siz];
66             f[i][j][k]%=MOD;
67           } //DP
68     }
69     ans=(ans+f[sr][sb][sg])%MOD;
70   }
71   ans=ans+fact(n)*inv(fact(sr))*inv(fact(sb))*inv(fact(sg));
72   printf("%d\n",(ans*inv(m+1))%MOD);
73   return 0;
74 }
75 //================fuction code====================
76 int quickpow(int a,int Exp){
77   if (Exp==0) return 1;
78   if (Exp==1) return a;
79   int temp=quickpow(a,Exp/2);
80   temp=(temp*temp)%MOD;
81   if (Exp&1) temp=(temp*a)%MOD;
82   return temp;
83 }

Code

时间: 2024-10-15 07:15:45

【HNOI2008】Cards BZOJ 1004的相关文章

【BZOJ】【1004】【HNOI2008】Cards

Burnside/Polya+背包DP 这道题目是等价类计数裸题吧……>_> 题解:http://m.blog.csdn.net/blog/njlcazl_11109/8316340 啊其实重点还是:找出每个置换下的不动点数目 这道题比较特殊,牌的数量是限定的,所以只能DP来搞……(dp[R][G][B]表示的是R张红牌,G张绿牌,B张蓝牌在当前这个置换下,有多少种方案是会置换回自身的) 恒等置换单独处理一下即可(其实就是总染色数,多重集排列数吧……$\frac{N!}{R!G!B!}$) 最

Cards bzoj 1004

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

【BZOJ】【1009】 【HNOI2008】GT考试

DP/KMP/矩阵乘法 好神的题啊……跪了跪了 $n\leq 10^9$是什么鬼……我们还是先不要考虑这个鬼畜的玩意了>_> 用类似数位DP的思路,我们可以想到一个DP方程:$f[i][j]$表示前 i 位数字,它的最后 j 位与不吉利串匹配的方案数,显然有$ans=\sum_{i=0}^x f[n][i]$ 然后就是转移的问题了= =那么依旧按照数位DP的想法(其实是硬扯到那的吧……怎么理解都可以,重点是明白转移方程)可以想到:从 i 转移到 i+1,有10种方案,其中一种会使得匹配长度+1

【BZOJ】【1006】【HNOI2008】神奇的国度

弦图最小染色/MCS算法 Orz PoPoQQQ  (UPD:ydc的写法好像更熟悉一些……(类似堆优化的Dij啊~ 先留个坑……明天再看一看……感觉好神奇>_<(完美消除序列之于弦图 就好似 拓扑序列之于DAG,所以弦图的问题许多都要靠这个完美消除序列来做) 1 /************************************************************** 2 Problem: 1006 3 User: Tunix 4 Language: C++ 5 Resu

【BZOJ】【1007】【HNOI2008】水平可见直线

计算几何初步 其实是维护一个类似下凸壳的东西?画图后发现其实斜率是单调递增的,交点的横坐标也是单调递增的,所以排序一下搞个单调栈来做就可以了…… 看了hzwer的做法…… 1 /************************************************************** 2 Problem: 1007 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:252 ms 7 Memory:2812 kb 8

【BZOJ】【1011】【HNOI2008】遥远的行星

神奇的思路题QAQ 玛雅看到这题我就醉了,什么玩意……5%的误差?果断膜拜@ydc神犇的题解: 就是因为不清楚如何应用那个答案误差不超过5%啦. 从没见过这么诡异的题一下就懵了,问到了方法之后都还半信半疑,直到后来发现真的很有效果. 就是小于2000的,我们n^2爆搞一下,大于两千的,由于α很小,i又大于2000,所以i-i×α挺大的,准确的说1/(i-1)与1/(i-i×α)差不多大…… 那么对于大于2000的i,假如他能弄到k,我们只要把公式中的i-j都变成i-k/2就可以了,误差不会很大.

【BZOJ】【1010】【HNOI2008】玩具装箱Toy

DP/斜率优化 根据题目描述很容易列出动规方程:$$ f[i]=min\{ f[j]+(s[i]-s[j]+i-j-1-L)^2 \}$$ 其中 $$s[i]=\sum_{k=1}^{i} c[k] $$ 而$x$即为$s[i]-s[j]+i-j-1$ 这个$x$的表示实在太不好看,我们容易发现$i-j$其实是可以跟$s[i]-s[j]$合到一起的,即令 $c[i]=c[i]+1$,则$s[i]=\sum_{k=1}^{i} (c[i]+1)=\sum_{k=1}^{i}c[i]+i $,所以$

动态规划(斜率优化):BZOJ 1010 【HNOI2008】 玩具装箱

玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 8218  Solved: 3233[Submit] Description P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维 容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的. 同时如果一个一维

BZOJ 1006 【HNOI2008】 神奇的国度

题目链接:神奇的国度 一篇论文题--神奇的弦图,神奇的MCS-- 感觉我没有什么需要多说的,这里简单介绍一下MCS: 我们给每个点记录一个权值,从后往前依次确定完美消除序列中的点,每次选择权值最大的一个点(相同的话随意选一个)放到当前完美消除序列中的位置,然后把相邻的所有点权值加\(1\).一路到底即可得到一种完美消除序列.使用链表可以将复杂度优化到\(O(n+m)\).在弦图中有 最小染色=团数,求完美消除序列的时候顺便统计即可. 好吧,上面实在扯淡.其实还是要看\(CDQ\)当年的\(ppt