卧薪尝胆,厚积薄发。
      
    
            TJOI2018 游园会
        
        
        Description:
给一个串
$S$
,对于每个
$i$
求出有多少个
$T$
满足
$LCS(S,T)=i$
并且
$T$
中不出现连续子串
$NOI$
,
$\Sigma=NOI$
。
$1\leqslant n\leqslant 10^3,1\leqslant |S|\leqslant 15$
Solution:
显然的DP套DP,再加一维表示和NOI的匹配长度即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
inline int rd()
{
	register int res = 0,f = 1;register char c = getchar();
	while(!isdigit(c)){if(c == '-')f = -1;c = getchar();}
	while(isdigit(c))res = (res << 1) + (res << 3) + c - '0',c = getchar();
	return res * f;
}
int n,m;
#define MAXN 1010
#define MAXM 17
#define MAX 15
char c[MAXM];
int toint(char c)
{
	if(c == 'N')return 0;if(c == 'O')return 1;
	if(c == 'I')return 2;
}
int S[MAXM];
int g[1 << MAX][3][3];
int dp[2][MAXN];
int bit(int s,int i){return ((s >> (i - 1)) & 1);}
int f[2][1 << MAX][3];
int ans[MAXM];
#define MOD 1000000007
int main()
{
	scanf("%d%d",&n,&m);
	scanf("%s",c + 1);
	for(int i = 1;i <= m;++i)S[i] = toint(c[i]);
	for(int i = 0;i < (1 << m);++i)
	{
		for(int x = 0;x < 3;++x)
		{
			for(int l = 0;l < 3;++l)
			{
				for(int k = 1;k <= m;++k)dp[0][k] = dp[0][k - 1] + bit(i,k);
				for(int k = 1;k <= m;++k)dp[1][k] = max(max(dp[0][k],dp[1][k - 1]),dp[0][k - 1] + (x == S[k]));
				int s = 0,len;
				for(int k = 1;k <= m;++k)s |= ((dp[1][k] - dp[1][k - 1]) << (k - 1));
				if(x == l)len = l + 1;
				else if(x == 0)len = 1;
				else len = 0;
				if(len == 3)g[i][x][l] = -1;
				else g[i][x][l] = s * 3 + len;
			}
		}
	}
	memset(f,0,sizeof(f));
	int cur = 0;
	f[0][0][0] = 1;
	for(int i = 1;i <= n;++i)
	{
		cur ^= 1;
		memset(f[cur],0,sizeof(f[cur]));
		for(int s = 0;s < (1 << m);++s)
		{
			for(int x = 0;x < 3;++x)
			{
				for(int l = 0;l < 3;++l)
				{
					int t = g[s][x][l] / 3,len = g[s][x][l] % 3;
					if(g[s][x][l] != -1)f[cur][t][len] = (f[cur][t][len] + f[cur ^ 1][s][l]) % MOD;
				}
			}
		}
	}
	memset(ans,0,sizeof(ans));
	for(int s = 0;s < (1 << m);++s)
	{
		int sum = 0;
		for(int k = 1;k <= m;++k)sum += (s >> (k - 1)) & 1;
		for(int l = 0;l < 3;++l)ans[sum] = (ans[sum] + f[cur][s][l]) % MOD;
	}
	for(int i = 0;i <= m;++i)printf("%d\n",ans[i]);	
	return 0;
}
 In tag:
DP-DP套DP
          In tag:
DP-DP套DP 
          
        
        Copyright © 2020
        
          wjh15101051
        
      
      ღゝ◡╹)ノ♡
     Date: Sat Mar 30 11:36:55 CST 2019
          Date: Sat Mar 30 11:36:55 CST 2019
           In Category:
          In Category:
           
         Timeline
            Timeline
           About
            About
           Toolbox
            Toolbox
           Friends
              Friends