博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

[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;
}
posted @ 2018-08-07 16:24  Allorkiya  阅读(284)  评论(0编辑  收藏  举报