大視野1079: [SCOI2008]着色方案

題目

Description

  有n個木塊排成一行,從左到右依次編號爲1~n。你有k種顏色的油漆,其中第i種顏色的油漆足夠塗ci個木塊。
所有油漆剛好足夠塗滿所有木塊,即c1+c2+...+ck=n。相鄰兩個木塊塗相同色顯得很難看,所以你希望統計任意兩
個相鄰木塊顏色不同的着色方案。

Input

  第一行爲一個正整數k,第二行包含k個整數c1, c2, ... , ck。

Output

  輸出一個整數,即方案總數模1,000,000,007的結果。

Sample Input

3

1 2 3
Sample Output

10
HINT

100%的數據滿足:1 <= k <= 15, 1 <= ci <= 5

解法

神奇的動態規劃,設一共有n種顏色,sum[i]表示sigma(c[j],1<=j<=i),dp[i][j]表示用了前i種顏色排成sum[i]個,其中有j個相鄰同色的方案數,如果用前i個的情況去推i+1的情況,就是往sum[i]箇中加入c[i+1]個,設把c[i+1]個分成k個同色的,而且不相鄰地插入到sum[i]箇中,設k箇中有h個插入到sum[i]中相鄰同色的地方,則k-h個插入到相鄰不同色的地方,C[i][j]表示在i中取j個的組合數。
那麼,這樣插入後會有多少個相鄰同色的呢,分成k組後會增加c[i+1]-k個,之後有會減少h個,所以是j+(c[i+1]-k)-h個。
然後把c[i+1]個分成k個有C[c[i+1]-1][k-1]種分法,把k組插入到sum[i+1]有C[j][h]*C[sum[i]+1-j][k-h]種方法。
所以動規方程是 dp[i+1][j+(c[i+1]-k)-h]+=C[c[i+1]-1][k-1]*dp[i][j]*C[j][h]*C[sum[i]+1-j][k-h],最後答案是dp[n][0]。

代碼

#include<cstdio>
#include<cstring>
#define LL long long
#define mod 1000000007
LL dp[20][80];
int sum[20];
int c[20];
LL C[85][85];
void pre()
{
	int i,j;
	for(i=0;i<=80;i++)
	{
		C[0][i]=0;
		C[i][0]=1;
	}
	for(i=1;i<=80;i++)
		for(j=1;j<=80;j++)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
int main()
{
	int n,i,j,k,h;
	pre();
	scanf("%d",&n);
	sum[0]=0;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&c[i]);
		sum[i]=sum[i-1]+c[i];
	}
	dp[1][c[1]-1]=1;
	for(i=1;i<n;i++)
		for(j=0;j<=sum[i]+1;j++)
			for(k=1;k<=c[i+1];k++)
				for(h=0;h<=j&&h<=k;h++)
					dp[i+1][j+(c[i+1]-k)-h]=(dp[i+1][j+(c[i+1]-k)-h]+C[c[i+1]-1][k-1]*dp[i][j]%mod*C[j][h]%mod*C[sum[i]+1-j][k-h]%mod)%mod;
	printf("%lld\n",dp[n][0]);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章