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;
}