bzoj-1079 着色方案(dp)

Time Limit:10000MS     Memory Limit:165888KB   
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

 

题意:

 

思路:

 

f[a][b][c][d][e][x]表示能涂一个格子的油漆有a种,能涂两个格子的油漆有b种...x表示的是上一次涂的是能涂x个格子的油漆;

f[a][b][c][d][e][x]=f[a-1][b][c][d][e]*(a-(x==2))+f[a+1][b-1][c][d][e]*(b-(x==3))+...+f[a][b][c][d+1][e-1]*(a-(x==6));

这个方程表示,剩下a,b,c,d,e,上次的是x,

假设这次要用可以涂k个格子的油漆,那么涂完这个格子,可以涂k个格子的油漆少了一种,可以涂k-1个格子的油漆多了一种;

这就是为什么b-1的时候a+1,c-1的时候b+1的原因;

还有就是相邻的格子的颜色不同,假设上一次用的是可以涂x个格子的油漆,那么上一次用完后的那种油漆就变成了一种可以涂x-1个格子的油漆了,那么这一次再选油漆的时候就不能再选可以涂x-1个格子的油漆的一种(这种上次一就用过了);所以对应的是*(a-(x==2))和*(b-(x==3))这些了;

 

AC代码:

 

//#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <queue>
#include <cmath>
#include <map>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
#define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss));

typedef  long long LL;
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + '0');
    putchar('\n');
}

const LL mod=1e9+7;
const double PI=acos(-1.0);
const LL inf=1e18;
const int N=2e3+10;
const int maxn=1005;
const double eps=1e-10;

int num[7];
LL f[17][17][17][17][17][6];
LL dp(int a,int b,int c,int d,int e,int x)
{
    if(f[a][b][c][d][e][x]!=0)return f[a][b][c][d][e][x];
    LL ans=0;
    if(a)ans=(ans+(a-(x==2))*dp(a-1,b,c,d,e,1))%mod;
    if(b)ans=(ans+(b-(x==3))*dp(a+1,b-1,c,d,e,2))%mod;
    if(c)ans=(ans+(c-(x==4))*dp(a,b+1,c-1,d,e,3))%mod;
    if(d)ans=(ans+(d-(x==5))*dp(a,b,c+1,d-1,e,4))%mod;
    if(e)ans=(ans+e*dp(a,b,c,d+1,e-1,5))%mod;
    f[a][b][c][d][e][x]=ans;
    return ans;
}
int main()
{
    int k,x;
    read(k);
    For(i,1,k)read(x),num[x]++;
    f[1][0][0][0][0][1]=1;
    cout<<dp(num[1],num[2],num[3],num[4],num[5],6)<<"\n";
        return 0;
}

 

posted @ 2016-07-12 18:25  LittlePointer  阅读(688)  评论(0编辑  收藏  举报