JZOJ 5192. 【NOI2017模拟7.2】容器 (dp)
https://gmoj.net/senior/#contest/show/2376/1
题解:
考虑把区间拆成左端点和右端点,\(T\)的限制相当于任何一个时候,没有匹配的左端点\(\le T\)
设\(f[i][p][q]\)表示刚刚确定了\(i\)的右括号,和\(i+1\)的左括号,匹配了\(p\)个区间,还有\(q\)左括号。
转移可以枚举下一步选多少,顺便分配是那些跳蚤选了这些左括号和右括号就行了。
一直纠结于用\(\frac{k!}{\prod a[i]!}\)去计算分配方案,事实上不用,这样也做不了。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int mo = 1011110011;
const int N = 45;
int n, k, t;
ll c[N][N];
ll f[N][N][N];
void add(ll &x, ll y) {
(x += y) %= mo;
}
int main() {
freopen("container.in", "r", stdin);
freopen("container.out", "w", stdout);
scanf("%d %d %d", &n, &k, &t);
fo(i, 0, 40) {
c[i][0] = 1;
fo(j, 1, i) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mo;
}
f[0][0][0] = 1;
n ++;
fo(i, 1, n) {
fo(p, 0, k) fo(q, 0, k) if(f[i - 1][p][q]) {
fo(u, 0, q) fo(v, 0, k - p - q) {
int np = p + u, nq = q - u + v;
if(np + nq > k || nq > t) continue;
add(f[i][np][nq], f[i - 1][p][q] * c[q][u] % mo * c[k - p - q][v]);
}
}
}
ll ans = f[n][k][0];
pp("%lld\n", ans);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址