HDU 4532 湫秋系列故事——安排座位(组合DP)

题目链接

比赛的时候,无想法。。看了题解之后,很难理解。。上个CF上的组合DP,感觉都有类似之处把。。。

dp[i][j]表示前i组有j个相邻左右都是相同系的位置。

讲当前a[i]个人,可以分为k组,枚举u,假如这k组里,有u组在j个位置之中。此时相连的就变为j-u+a[i]-k了。

各种组合乘起来。

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 #define MOD 1000000007
 5 #define LL __int64
 6 LL c[501][501];
 7 int a[501];
 8 LL dp[51][501];
 9 LL fact[51];
10 int Min(int a,int b)
11 {
12     return a < b ? a:b;
13 }
14 int main()
15 {
16     int i,j,k,u,n,t,cas = 1,sum,minz;
17     for(i = 0;i <= 500;i ++)
18     {
19         c[i][0] = 1;
20     }
21     for(i = 1;i <= 500;i ++)
22     {
23         for(j = 1;j <= 500;j ++)
24         c[i][j] = (c[i-1][j-1] + c[i-1][j])%MOD;
25     }
26     fact[0] = 1;
27     for(i = 1;i <= 50;i ++)
28     {
29         fact[i] = (fact[i-1] * i)%MOD;
30     }
31     scanf("%d",&t);
32     while(cas <= t)
33     {
34         scanf("%d",&n);
35         memset(dp,0,sizeof(dp));
36         sum = 0;
37         for(i = 1;i <= n;i ++)
38         scanf("%d",&a[i]);
39         dp[1][a[1]-1] = 1;
40         sum = a[1];
41         for(i = 2;i <= n;i ++)
42         {
43             for(j = 0;j < sum;j ++)
44             {
45                 minz = Min(a[i],sum+1);
46                 for(k = 1;k <= minz;k ++)
47                 {
48                     for(u = 0;u <= j&&u <= k;u ++)
49                     {
50                         dp[i][j-u+a[i]-k] = (dp[i][j-u+a[i]-k]+(((((dp[i-1][j]*c[j][u])%MOD)*c[sum+1-j][k-u])%MOD)*c[a[i]-1][k-1]))%MOD;
51                     }
52                 }
53             }
54             sum += a[i];
55         }
56         LL ans = dp[n][0];
57         for(i = 1;i <= n;i ++)
58         {
59             ans = (ans*fact[a[i]])%MOD;
60         }
61         printf("Case %d: %I64d\n",cas,ans);
62         cas ++;
63     }
64     return 0;
65 }

 

 

 

posted @ 2013-04-10 15:57  Naix_x  阅读(381)  评论(4编辑  收藏  举报