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 }