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 }

你可能感兴趣的:(uva)