【區間DP】BZOJ1055(HAOI2008)[玩具取名]題解
阿新 • • 發佈:2019-01-09
題目概述
JZ選擇WING四個字母中的任意一個字母作為JZ的基本網名。然後JZ會根據自己的喜好,將名字中任意一個字母用“WING”中任意兩個字母代替(會給出字母能變成哪些雙字母),使得自己的網名能夠擴充得很長。現在,他想請你猜猜某一個很長的網名,最初可能是由哪幾個字母變形過來的。
解題報告
DP功底不行了啊QAQ,這應該不算很難的區間DP吧……
定義 表示 是否能變成 ,然後只需要列舉斷開的地方,轉移一下就行了。
示例程式
#include<cstdio>
#include<cctype>
using namespace std;
const int maxn=200,maxe=4*16;
int n,ID[256],m[4],E,lnk[16],nxt[maxe+5],son[maxe+5];
char s[4];bool f[maxn+5][maxn+5][4];
inline char getupr() {char ch=getchar();while (!isupper(ch)) ch=getchar();return ch;}
#define Add(x,y) son[++E]=y,nxt[E]=lnk[x],lnk[x]=E
#define val(x,y) ((x)<<2|(y))
int main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
ID[s[0]='W']=0;ID[s[1]='I']=1;ID[s[2]='N']=2;ID[s[3]='G']=3;
for (int i=0;i<4;i++) scanf("%d",&m[i]);
for (int t=0;t<4;t++)
for (int now;m[t];m[t]--)
now=ID[getupr()],now=now<<2 |ID[getupr()],Add(now,t);
char lst=0,ch=getupr();
for (n=1;isupper(ch);lst=ch,ch=getchar(),n++){
f[n][n][ID[ch]]=true;if (!lst) continue;
for (int j=lnk[val(ID[lst],ID[ch])];j;j=nxt[j])
f[n-1][n][son[j]]=true;
}
for (int len=(n--,3);len<=n;len++)
for (int i=1,j=len;j<=n;i++,j++)
for (int k=i;k<j;k++)
for (int x=0;x<4;x++)
for (int y=0;y<4;y++)
if (f[i][k][x]&&f[k+1][j][y])
for (int e=lnk[val(x,y)];e;e=nxt[e])
f[i][j][son[e]]=true;
bool fl=false;for (int i=0;i<4;i++) if (f[1][n][i]) fl=true,putchar(s[i]);
return puts(fl?"":"The name is wrong!"),0;
}