BZOJ 1055: [HAOI2008]玩具取名
阿新 • • 發佈:2017-10-10
命名 str 哪些 desc color 一行 can script rip 字符串。表示這個玩具的名字。
II
WW
WW
IG
IIII
[數據範圍]
100%數據滿足Len<=200,W、I、N、G<=16
Description
某人有一套玩具,並想法給玩具命名。首先他選擇WING四個字母中的任意一個字母作為 玩具的基本名字。然後他會根據自己的喜好,將名字中任意一個字母用“WING”中任意兩個 字母代替,使得自己的名字能夠擴充得很長。現在,他想請你猜猜某一個很長的名字,最初 可能是由哪幾個字母變形過來的。Input
第一行四個整數W、I、N、G。表示每一個字母能由幾種兩個字母所替代。接下來W行,每行 兩個字母,表示W可以用這兩個字母替代。接下來I行,每行兩個字母,表示I可以用這兩個字母替代。 接下來N行,每行兩個字母,表示N可以用這兩個字母替代。接下來G行,每行兩個字母,表示G可以 用這兩個字母替代。最後一行一個長度不超過Len的Output
一行字符串,該名字可能由哪些字母變形而得到。(按照WING的順序輸出)如果給的名字不
能由任何一個字母變形而得到則輸出“The name is wrong!”
Sample Input
1 1 1 1II
WW
WW
IG
IIII
Sample Output
INHINT
W可以變成II所以IIII可以縮成WW IN均能變成WW所以WW又可以縮成I或者N 所以最終答案應 該按照“WING”的順序輸出IN
[數據範圍]
100%數據滿足Len<=200,W、I、N、G<=16
題目大意:
一個字母可以多個兩個字母合成,如W可以由WI合成也可以由GI合成。
給定一個字符串,求它最初是由哪幾個字母組成的。
題解:區間dp
f[l][r][i]表示區間[l,r]能否合成i這個字母。
轉移方程為 f[l][r][i]=f[l][r][i]||(f[l][mid][p]&&f[mid+1][r][g])
其中mid為區間的斷點,p,g為合成i的兩個字母。
代碼:1A好開心 -~
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int len; bool flag,f[220][220][5]; char a[220]; struct S{ string s[20]; int cnt; }c[5]; int main(){ scanf("%d%d%d%d",&c[1].cnt,&c[2].cnt,&c[3].cnt,&c[4].cnt); for(int i=1;i<=4;i++) for(int j=1;j<=c[i].cnt;j++) cin>>c[i].s[j]; scanf("%s",a+1);len=strlen(a+1); for(int i=1;i<=len;i++){ int g; if(a[i]==‘W‘)g=1; if(a[i]==‘I‘)g=2; if(a[i]==‘N‘)g=3; if(a[i]==‘G‘)g=4; f[i][i][g]=1; } for(int k=2;k<=len;k++){ for(int l=1;l+k-1<=len;l++){ int r=l+k-1; for(int mid=l;mid<r;mid++){ for(int i=1;i<=4;i++){ for(int j=1;j<=c[i].cnt;j++){ int g,p; if(c[i].s[j][0]==‘W‘)g=1;if(c[i].s[j][1]==‘W‘)p=1; if(c[i].s[j][0]==‘I‘)g=2;if(c[i].s[j][1]==‘I‘)p=2; if(c[i].s[j][0]==‘N‘)g=3;if(c[i].s[j][1]==‘N‘)p=3; if(c[i].s[j][0]==‘G‘)g=4;if(c[i].s[j][1]==‘G‘)p=4; f[l][r][i]=f[l][r][i]||(f[l][mid][g]&&f[mid+1][r][p]); } } } } } for(int i=1;i<=4;i++){ if(f[1][len][i]){ if(i==1)printf("W"); if(i==2)printf("I"); if(i==3)printf("N"); if(i==4)printf("G"); flag=true; } } if(!flag)printf("The name is wrong!"); return 0; }
BZOJ 1055: [HAOI2008]玩具取名