uva 11668 How Many Teams?

Sample Input                                     Output for Sample Input

3
2 2
sohelH-CSE samee-CSE
4 2
Blind-ECS sidky-CSE muntasir-CSC ShadowCoder-EEE
4 2

ABC-D1 DEF-D1 ghi-D2 jkl-D3

Case 1: 0
Case 2: 24
Case 3: 16


题意:给出n个人与这些人分别所属的公司,其中属于同一家公司的人不会超过3个人。将n个人任意排列(即有n!)中情况,按顺序将任意排列的n个人,每k个人一组(保证n%k==0),问满足每组不会有相同公司人的排列有多少个?

比赛的时候一直没往DP方面想,后来发现确实是一个很少见的dp或者是以前不知到的dp,想出了状态转移到是挺好想的了。

状态最后是间接经过肖神提示得到的,dp[i][j][p]表示还剩i个公司有3个人,j个公司有2个人,p个公司有1个人,的情况有多少种。

首先,最终要求的肯定就是dp[0][0][0]肯定很容易想了;初始值就是dp[x][y][z]=1,x,y,z就是给的情况

其次如果将i,j,p逆着递推,这样就正好得到最终结果,dp[i][j][p]可以有很多中转移情况,应为组成新的一组需要k个人,而这k个人是从i,j,p那一快转移过来都有可能,所以实现预处理好所以情况,到时候一一枚举就可以了;

最后转移的过程有很多排列数和组合数有区别的地方要注意,例如从i个人中如果要选ti个人,那么就会有C(i,ti)*(3^ti)种情况,对于j,p同理,最后选出来的k个人,同样也还是要有一种顺序而言,所以又是k!,写的过程中注意及时取模就ok了。

另外输入其实也看起来处理挺麻烦的,但其实可以用string中的substr,和find函数,然后就挺好写了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<map>
 7 #define see(x) cout<<#x<<":"<<x<<endl;
 8 using namespace std;
 9 const int maxn = 105;
10 const int mod = 1234;
11 int dp[maxn][maxn][maxn], cntt[maxn], c[maxn][maxn], way[maxn][5];
12 int exp22[maxn], exp3[maxn], f[maxn];
13 string str, tmp;
14 map<string,int> cha;
15 int main(){
16     int t, i, j, p, l, m, cas=1, n, k, cnt, ti, tj, tp;
17     int x, y, z;
18     c[0][0]=1;
19     for(i=1;i<maxn;i++){
20         c[i][0] = 1;
21         for(j=1;j<=i;j++){
22             c[i][j] = (c[i-1][j-1]+c[i-1][j])%mod;
23         }
24     }
25     exp22[0] = exp3[0] = f[0] = 1;
26     for(i=1;i<maxn;i++){
27         exp22[i] = (exp22[i-1]*2)%mod;
28         exp3[i] = (exp3[i-1]*3)%mod;
29         f[i] = (f[i-1]*i)%mod;
30     }
31     scanf("%d",&t);
32     while(t--){
33         scanf("%d%d",&n,&k);
34         m = 0;
35         for(i=0;i<=k;i++){
36             for(j=0;j<=k;j++){
37                 for(p=0;p<=k;p++){
38                     if((i+j+p)==k){
39                         way[m][1] = i;
40                         way[m][2] = j;
41                         way[m][3] = p;
42                         m++;
43                     }
44                 }
45             }
46         }
47         cha.clear();
48         cnt=0;
49         memset(cntt,0,sizeof(cntt));
50         x=y=z=0;
51         for(i=0;i<n;i++){
52             cin>>str;
53             p = str.find('-');
54             tmp = str.substr(p+1,str.size()-p-1);
55             if(!cha[tmp]){
56                 cha[tmp] = ++cnt;
57                 cntt[cnt]++;
58             }
59             else{
60                 cntt[cha[tmp]]++;
61                 if(cntt[cha[tmp]]==3){
62                     z++;
63                 }
64             }
65             y = n-z*2-cnt;
66             x = cnt-z-y;
67         }
68         memset(dp,0,sizeof(dp));
69         dp[z][y][x] = 1;
70         for(i=n;i>=0;i--){
71             for(j=n;j>=0;j--){
72                 for(p=n;p>=0;p--){
73                     if(dp[i][j][p]){
74                         for(l=0;l<m;l++){
75                             ti = way[l][1]; tj = way[l][2]; tp = way[l][3];
76                             if(i>=ti&&j>=tj&&p>=tp){
77                                 dp[i-ti][j+ti-tj][p+tj-tp] += dp[i][j][p]*c[i][ti]%mod*exp3[ti]%mod*c[j][tj]%mod*exp22[tj]%mod*c[p][tp]%mod*f[k]%mod;
78                                 dp[i-ti][j+ti-tj][p+tj-tp] %= mod;
79                             }
80                         }
81                     }
82                 }
83             }
84         }
85         printf("Case %d: %d\n",cas++,dp[0][0][0]);
86     }
87     return 0;
88 }
原文地址:https://www.cnblogs.com/celia01/p/2645757.html