首先这题只存在单字母变成两个字母,不能从双子母变成单字母。
所以进行操作得区间最多只有1~n,
考虑区间dp
令f i,j,k表示在i~j这个区间凑成 k是否可行。
用'1''2''3''4'替代'W''I''N''G'
然后转移就可以很简单得写出来
fijk |= f i,p,q1 & f i,p+1,q2
c++代码如下:
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<cctype>
#include<vector>
#define id(x) (x == 'W' ? 1 : x == 'I' ? 2 :x == 'N' ? 3 : 4)
#define rep(i,x,y) for(register int i = x;i <= y;++ i)
#define repd(i,x,y) for(register int i = x ; i >= y;-- i)
using namespace std;
template<typename T>inline void read(T&x)
{
char c;int sign = 1;x = 0;
do { c = getchar(); if(c == '0') sign = 1; }while(!isdigit(c));
do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
x *= sign;
}
const int N = 201;
int f[N][N][N],t[5][N],a[N],x[5];
char s[N];
bool dfs(int l,int r,int k)
{
if(l > r) return true;
if(l == r) return f[l][r][k] = k == a[l];
if(~f[l][r][k]) return f[l][r][k];
rep(i,1,x[k])
rep(j,l,r - 1)
if(dfs(l,j,t[k][i]/10) && dfs(j + 1,r,t[k][i]%10))
return f[l][r][k] = 1;
return f[l][r][k] = 0;
}
int main()
{
memset(f,-1,sizeof f);
read(x[1]); read(x[2]); read(x[3]); read(x[4]);
rep(j,1,4) rep(i,1,x[j])
{
scanf("%s",s);
t[j][i] = id(s[0]) * 10 + id(s[1]);
}
scanf("%s",s + 1);
int len = strlen(s + 1);
rep(i,1,len) a[i] = id(s[i]);
bool flag = 0;
rep(i,1,4) if(dfs(1,len,i)) flag = 1,printf(i == 1 ? "W" : i == 2 ? "I" : i == 3 ? "N" : "G");
if(!flag) puts("The name is wrong!");
return 0;
}