1055: [HAOI2008]玩具取名
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 887 Solved: 518
[ Submit][ Status]
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 1
II
WW
WW
IG
IIII
II
WW
WW
IG
IIII
Sample Output
IN
HINT
W可以变成II所以IIII可以缩成WW IN均能变成WW所以WW又可以缩成I或者N 所以最终答案应该按照“WING”的顺序输出IN
[数据范围]
100%数据满足Len<=200,W、I、N、G<=16
【题解】
1055: 题目大意是 给你一个变形后的串,问你它可能是由哪几个字符变化得来的。 一、 我想的,最后的答案只有四个,所以或许可以一个一个试出来。 那么得到目标的字符串,需要 len-1 次变化。 分治思想: I I I I \ / \ / W W \ / I(N) dfs(n) =(16)* len(n) * { dfs(x) + dfs(n-x) };
很明显这是铁定TLE 的,于是我苦思冥想,突然想到加上记忆化怎么样。
如果加上记忆化 状态数 最多是 len*len*4 中,加上每种状态 的 16 次枚举哪一个变化,得 O( n*n*64 )的时间复杂度,就可以过了。
#include<cstdio> #include<cstring> #include<cstdlib> int a[26],n[4],f[4][210][210],len; char c[4][18][3],s[210]; void dfs(int x,int L,int R) { if(f[x][L][R]!=(-1))return; if(L==R) { f[x][L][R]=(x==a[s[L]-'A']); return; } for(int i=1;i<=n[x];i++) { for(int j=L;j<R;j++) { if(j==L && s[L]!=c[x][i][1])continue; if((j+1)==R && s[R]!=c[x][i][2])continue; if(!f[a[c[x][i][1]-'A']][L][j])continue; if(!f[a[c[x][i][2]-'A']][j+1][R])continue; if(f[a[c[x][i][1]-'A']][L][j]==(-1))dfs(a[c[x][i][1]-'A'],L,j); if(!f[a[c[x][i][1]-'A']][L][j])continue; if(f[a[c[x][i][2]-'A']][j+1][R]==(-1))dfs(a[c[x][i][2]-'A'],j+1,R); if(f[a[c[x][i][2]-'A']][j+1][R]==1 && f[a[c[x][i][1]-'A']][L][j]==1) { f[x][L][R]=1; break; } } if(f[x][L][R]!=(-1))break; } if(f[x][L][R]==(-1))f[x][L][R]=0; } int main() { scanf("%d%d%d%d",&n[0],&n[1],&n[2],&n[3]); memset(f,-1,sizeof(f)); a['W'-'A']=0; a['I'-'A']=1; a['N'-'A']=2; a['G'-'A']=3; for(int i=1;i<=n[0];i++)scanf("%s",c[0][i]+1); for(int i=1;i<=n[1];i++)scanf("%s",c[1][i]+1); for(int i=1;i<=n[2];i++)scanf("%s",c[2][i]+1); for(int i=1;i<=n[3];i++)scanf("%s",c[3][i]+1); scanf("%s",s+1); len=strlen(s+1); int key=0; for(int i=0;i<4;i++) { dfs(i,1,len); if(f[i][1][len]==1) { switch (i) { case 0:printf("W"); break; case 1:printf("I"); break; case 2:printf("N"); break; case 3:printf("G"); break; } key=1; } } if(!key)printf("The name is wrong!"); printf("\n"); return 0; }