[TJOI 2018]游园会

题意:求NOI的合法串。。。

思路:

首先这个似乎和后缀自动机没关系(话说TJ不考后缀自动机??),其实就是一个\(DP\)\(DP\),考虑如果不看兑奖串就是一个LCS,当出现时多记一维即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
const int mod = 1e9+7;
int bit[maxn];
int t[maxn][3];
int dp[21];
int g[21];
int f[2][maxn][3][3];
int ans[21];
int n,m;
int k;
int a[21];
char s[21];
int nw = 1;
int nxt;
inline int read() {
    int q=0,f=1;char ch = getchar();
    while(!isdigit(ch)) {
        if(ch=='-') f = -1;ch = getchar();
    }
    while(isdigit(ch)) {
        q=q*10+ch-'0';ch = getchar();
    }
    return q*f;
}
inline void upd(int &x,int y) {
    x += y;
    if(x >= mod) x -= mod;
}

int main () {
    m = read(),n = read();
    scanf("%s",s+1);
    int lim = (1 << n);
    for(int i = 1;i < lim; ++i) {
        bit[i] = bit[i >> 1] + (i & 1);
    }
    for(int i = 1;i <= n; ++i) {
        if(s[i] == 'N') a[i] = 0;
        if(s[i] == 'O') a[i] = 1;
        if(s[i] == 'I') a[i] = 2;
    }
    for(int k = 0;k < lim; ++k) {
        for(int i = 1;i <= n; ++i) {
            dp[i] = dp[i - 1] + (k >> (n - i) & 1);
        }
        for(int i = 0;i < 3; ++i) {
            for(int j = 1;j <= n; ++j) {
                if(i == a[j]) {
                    g[j] = dp[j - 1] + 1;
                }
                else g[j] = max(g[j - 1],dp[j]);
            }
            for(int j = 1;j <= n; ++j) {
                if(g[j] == g[j - 1] + 1) {
                    t[k][i] |= 1 <<n - j;
                }
            }
        }
    }
    f[0][0][0][0] = 1;
    for(int i = 1;i <= m; ++i) {
        swap(nw,nxt);
        for(int j = 0;j < lim; ++j) {
            memset(f[nxt][j],0,sizeof(f[nxt][j]));
        }
        if(i <= 2) {
            for(int j = 0;j < lim; ++j) {
                for(int k = 0;k < 3; ++k) {
                    for(int l = 0;l < 3; ++l) {
                        if(f[nw][j][k][l])
                        for(int r = 0;r < 3; ++r) {
                            upd(f[nxt][t[j][r]][l][r],f[nw][j][k][l]);
                        }
                    }
                }
            }
        }
        else {
            for(int j = 0;j < lim ;++j) {
                for(int k = 0;k < 3; ++k) {
                    for(int l = 0;l < 3; ++l) {
                        if(f[nw][j][k][l]) {
                            int res = f[nw][j][k][l];
                            for(int r = 0;r < 3; ++r) {
                                if(!k && l == 1 && r == 2) continue;
                                upd(f[nxt][t[j][r]][l][r],res);
                            }
                        }
                    }
                }
            }
        }
    }
    for(int i = 0;i < lim; ++i) {
        for(int j = 0;j < 3; ++j) {
            for(int k = 0;k < 3 ; ++k) {
                upd(ans[bit[i]],f[nxt][i][j][k]);
            }
        }
    }
    for(int i = 0;i <= n; ++i) printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/akoasm/p/9437767.html
今日推荐