jzoj 3424. 【NOIP2013模拟】粉刷匠

Description

赫克托是一个魁梧的粉刷匠,而且非常喜欢思考= =

现在,神庙里有N根排列成一直线的石柱,从1到N标号,长老要求用油漆将这些石柱重新粉刷一遍。赫克托有K桶颜色各不相同的油漆,第i桶油漆恰好可以粉刷Ci根石柱,并且,C1+C2+C3…CK=N(即粉刷N根石柱正好用完所有的油漆)。长老为了刁难赫克托,要求相邻的石柱颜色不能相同。

喜欢思考的赫克托不仅没有立刻开始粉刷,反而开始琢磨一些奇怪的问题,比如,一共有多少种粉刷的方案?

为了让赫克托尽快开始粉刷,请你尽快告诉他答案。

Input

第一行一个正整数T,表示测试数据组数

对于每一组测试数据数据:

第1行:一个正整数K

第2行:K个正整数,表示第i桶油漆可以粉刷的石柱个数,Ci。

Output

对于每组输入数据,输出一行一个整数,表示粉刷的方案数mod 1000000007。

Sample Input

3
3
1 2 3
5
2 2 2 2 2
10
1 1 2 2 3 3 4 4 5 5

Sample Output

10
39480
85937576

Data Constraint

30% N≤10, T≤5
50% N≤15, T≤5
80% K≤15,Ci≤5,T≤500
100% K≤15,Ci≤6,T≤2000

Solution

一开始以为是一道结论题,没想到竟然是DP。
我们设\(f[i][j]\)表示刷到第i种颜色,当前有j个相邻柱子颜色相同的方案数。
记刷到现在的颜色块数为\(S\)\(c[1]\)~\(c[i]\)
对于第\(i+1\)种颜色,能刷\(c[i+1]\)次。
而我们把它分成k块,插入已有块中。
而其中有\(l\)块是插在相邻柱子颜色相同的中间。
如此,便可得出转移方程:
\[f[i+1][j+c[i+1-k-l]]+=f[i][j]*C(j,l)*C(c[i+1]-1,k-1)*C(n-j+1,k-l)\]

Code

#include <cstdio>
#include <cstring>
#define K 16
#define N 110
#define mo 1000000007
#define ll long long
#define mem(a, x) memset(a, x, sizeof a)
#define fo(x, a, b) for (int x = a; x <= b; x++)
#define fd(x, a, b) for (int x = a; x >= b; x--)
using namespace std;
int T, n, m, c[N];
ll f[N][N], jc[N], ny[N];

inline int read()
{
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x;
}

ll ksm(ll x, int y)
{
    ll s = 1;
    while (y)
    {
        if (y & 1) s = s * x % mo;
        x = x * x % mo; y >>= 1;
    }
    return s;
}

ll C(ll x, ll y) {return jc[x] * ny[y] % mo * ny[x - y] % mo;}

int main()
{
    freopen("paint.in", "r", stdin);
    freopen("paint.out", "w", stdout);
    jc[0] = 1; fo(i, 1, 90) jc[i] = jc[i - 1] * i % mo;
    ny[90] = ksm(jc[90], mo - 2);
    fd(i, 89, 0) ny[i] = ny[i + 1] * (i + 1) % mo;
    T = read();
    while (T--)
    {
        m = read(); n = 0;
        fo(i, 1, m) c[i] = read();
        mem(f, 0);
        f[1][c[1] - 1] = 1;
        fo(i, 1, m - 1)
        {
            n += c[i];
            fo(j, 0, n)
                fo(k, 1, c[i + 1])
                    fo(l, 0, (j < k ? j : k))
                        f[i + 1][j + c[i + 1] - k - l] += f[i][j] * C(j, l) % mo * C(c[i + 1] - 1, k - 1) % mo * C(n - j + 1, k - l) % mo;
        }
        printf("%lld\n", f[m][0] % mo);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/jz929/p/11286421.html