bzoj2616:SPOJ PERIODNI

Pre

调了好久好久。(QAQ)

高高兴兴的打了一个(DP)数组的转移的程序,直接(T)掉,后来看了题解发现有优化。

Solution

状态转移有三个部分组成,一个是左右子树,一个是矩形。

依次设置为(i,j,k),可以枚举,时间复杂度太高。

新开一个数组,存下当前状态下的(i+j)的总答案,时间复杂度(O(n^2)),在枚举(k),状态转移,时间复杂度(O(n^2))

Code

#include<bits/stdc++.h>
#define ll long long
using namespace std; 

const int mod = 1000000007, N = 550, M = 1000000 + 5;
int a[N], n, K;
int stk[N], top;
int ch[N][2], fa[N], sz[N];
ll dp[N][N], fac[M], f[N][N];
inline ll Pow (ll u, ll v) {
	ll tot = 1, base = u;
	while (v) {
		if (v % 2 == 1) {
			tot = tot * base % mod;
		}
		base = base * base % mod;
		v /= 2;
	}
	return tot;
}
inline ll C (ll u, ll v) {
	return fac[u] * Pow (fac[v], mod - 2) % mod * Pow (fac[u - v], mod - 2) % mod;
}
inline void dfs (int p, int v) {
	sz[p]++;
	if (ch[p][0]) {dfs (ch[p][0], a[p]);sz[p] += sz[ch[p][0]];}
	if (ch[p][1]) {dfs (ch[p][1], a[p]);sz[p] += sz[ch[p][1]];}
	for (int i = 0; i <= K; ++i) {
		for (int j = 0; j <= K; ++j) {
			if (i + j > K) {break;}
			f[p][i + j] = (f[p][i + j] + dp[ch[p][0]][i] * dp[ch[p][1]][j] % mod) % mod;
		}
	}
	for (int i = 0; i <= K; ++i) {
		if (i > a[p] - v) {break;}
		for (int j = 0; j <= K; ++j) {
			if (i + j > K || i + j > sz[p]) {break;}
			dp[p][i + j] = (dp[p][i + j] + f[p][j] * fac[a[p] - v] % mod * Pow (fac[a[p] - v - i], mod - 2) % mod * C (sz[p] - j, i) % mod) % mod;
		}
	}
}
int main () {
	scanf ("%d%d", &n, &K);
	fac[0] = 1; f[0][0] = 1; dp[0][0] = 1;
	for (int i = 1; i <= M - 5; ++i) {
		fac[i] = fac[i - 1] * i % mod;
	}
	for (int i = 1; i <= n; ++i) {
		scanf ("%d", &a[i]);
		while (top > 0 && a[stk[top]] > a[i]) {ch[i][0] = stk[top], top--;}
		if (ch[fa[ch[i][0]]][0] == ch[i][0]) {ch[fa[ch[i][0]]][0] = 0;}
		else {ch[fa[ch[i][0]]][1] = 0;}
		fa[ch[i][0]] = i;
		fa[i] = stk[top];
		if (fa[i]) {ch[fa[i]][1] = i;}
		stk[++top] = i;
	}
	int rt = 0;
	for (int i = 1; i <= n; ++i) {if (!fa[i]) {rt = i;break;}}
	dfs (rt, 0);
	printf ("%lld
", dp[rt][K] % mod);
	return 0;
}

Conclusion

这个优化方法有意思。

原文地址:https://www.cnblogs.com/ChiTongZ/p/11224383.html