【BZOJ2616】SPOJ PERIODNI

【题目链接】

【思路要点】

  • 笛卡尔树DP,先构建笛卡尔树。
  • 在本题中,我们可以把笛卡尔树的一个节点看做一个矩形,父节点的矩形在横坐标上包含子节点的矩形。
  • 记\(F_{i,j}\)表示在\(i\)的子树中放置\(j\)个车的方案数。
  • 转移时先FFT暴力合并子树信息:\(tmp_{i}=\sum_{j=0}^{i}F_{lc,j}*F_{rc,i-j}\)。
  • 然后再处理当前节点对应的矩形的转移:\(F_{now,i}=\sum_{j=0}^{i}tmp_{i-j}*j!*\binom{H}{j}*\binom{W-(i-j)}{j}\),其中\(H\)和\(W\)分别代表当前矩形的高度和宽度。
  • 时间复杂度\(O(NK^2)\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 505;
const int MAXV = 1e6 + 5;
const int P = 1e9 + 7;
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, k, top, stk[MAXN];
int lc[MAXN], rc[MAXN], val[MAXN], w[MAXN];
long long fac[MAXV], inv[MAXV];
long long tmp[MAXN], dp[MAXN][MAXN];
long long getc(int x, int y) {
	if (y > x || y < 0) return 0;
	else return fac[x] * inv[y] % P * inv[x - y] % P;
}
long long power(long long x, long long y) {
	if (y == 0) return 1;
	long long tmp = power(x, y / 2);
	if (y % 2 == 0) return tmp * tmp % P;
	else return tmp * tmp % P * x % P;
}
void work(int pos, int last) {
	int delta = val[pos] - last;
	w[pos] = 1;
	if (lc[pos]) work(lc[pos], val[pos]), w[pos] += w[lc[pos]];
	if (rc[pos]) work(rc[pos], val[pos]), w[pos] += w[rc[pos]];
	memset(tmp, 0, sizeof(tmp));
	for (int i = 0; i <= w[pos]; i++) {
		for (int j = 0; j <= i; j++)
			tmp[i] += dp[lc[pos]][j] * dp[rc[pos]][i - j] % P;
		tmp[i] %= P;
	}
	for (int i = 0; i <= w[pos]; i++) {
		for (int j = 0; j <= i; j++)
			dp[pos][i] += tmp[i - j] * fac[j] % P * getc(delta, j) % P * getc(w[pos] - (i - j), j) % P;
		dp[pos][i] %= P;
	}
}
int main() {
	read(n), read(k);
	for (int i = 1; i <= n; i++) {
		read(val[i]);
		bool flg = false;
		while (val[i] < val[stk[top]]) top--, flg = true;
		rc[stk[top]] = i;
		if (flg) lc[i] = stk[top + 1];
		stk[++top] = i;
	}
	dp[0][0] = 1;
	fac[0] = 1;
	for (int i = 1; i < MAXV; i++)
		fac[i] = fac[i - 1] * i % P;
	inv[MAXV - 1] = power(fac[MAXV - 1], P - 2);
	for (int i = MAXV - 2; i >= 0; i--)
		inv[i] = inv[i + 1] * (i + 1) % P;
	work(rc[0], 0);
	writeln(dp[rc[0]][k]);
	return 0;
}

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页