题意:求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;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章