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\n", dp[rt][K] % mod);
    return 0;
}

Conclusion

这个优化方法有意思。

猜你喜欢

转载自www.cnblogs.com/ChiTongZ/p/11224383.html