BZOJ1055: [HAOI2008]玩具取名
区间Dp
题解:
设f[l][r][x]
表示
[l,r]
区间能否变成
x
这个字母。
转移:枚举最后一次合并的划分点,枚举
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#define MP make_pair
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
typedef pair<int,int> pii;
const int N = 205;
map<char,int> dic; map<int,char> redic;
int atot,btot,ctot,dtot;
vector<pii> edge[5];
int f[N][N][5];
int n; char str[N];
void input(){
cin>>atot>>btot>>ctot>>dtot;
char tp[5];
for(int i=1;i<=atot;i++){
scanf("%s",tp);
edge[1].push_back(MP(dic[tp[0]],dic[tp[1]]));
}
for(int i=1;i<=btot;i++){
scanf("%s",tp);
edge[2].push_back(MP(dic[tp[0]],dic[tp[1]]));
}
for(int i=1;i<=ctot;i++){
scanf("%s",tp);
edge[3].push_back(MP(dic[tp[0]],dic[tp[1]]));
}
for(int i=1;i<=dtot;i++){
scanf("%s",tp);
edge[4].push_back(MP(dic[tp[0]],dic[tp[1]]));
}
scanf("%s",str+1); n=strlen(str+1);
}
int dp(int l,int r,int x){
// D(l); D(r); D(x); E;
int &ans = f[l][r][x];
if(ans!=-1) return ans;
if(l==r){ return ans=(dic[str[l]]==x); }
for(int i=l;i<r;i++){
for(int j=0;j<edge[x].size();j++){
pii t=edge[x][j];
if(dp(l,i,t.first) && dp(i+1,r,t.second)){
return ans=1;
}
}
}
return ans=0;
}
void init(){
memset(f,-1,sizeof(f));
dic['W']=1; dic['I']=2; dic['N']=3; dic['G']=4;
redic[1]='W'; redic[2]='I'; redic[3]='N'; redic[4]='G';
}
int main(){
freopen("a.in","r",stdin);
init(); input();
int can=0;
for(int i=1;i<=4;i++){
if(dp(1,n,i)){ cout<<redic[i]; can++; }
}
if(!can){ puts("The name is wrong!"); }
else cout<<endl;
}