第一眼:什么鬼东西ヾ(。`Д´。)
第二眼:显然,这道题要分段处理 类似[TJOI2018]碱基序列\ (建议做一做也是Hash+DP)\ 那你怎么第一眼没看出来
Hash处理+DP==AC
直接上代码 (码风奇特请谅解,注释还算详细)
#include<cstdio> #include<cstring> #define _for(i,a,b) for(register int i=(a);i<=(b);i=-~i) #define __for(i,a,b) for(register int i=(a);i>=(b);i=~-i) #define Re register int using namespace std; typedef long long ll; typedef unsigned long long ull; const int inf=2147483647,N=100000+20,M=11; inline int re(){int x=0,f=0; char ch=getchar(); while(ch>'9'||ch<'0') f|=ch=='-',ch=getchar(); while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } char s1[N],s2[N]; ull hash1[110],hash2[N],p[N]; int len[110],n,cnt,hl,len2,num; bool f[110][N];//懒得压维(按顺序处理到第几组、对应字符串中的哪一位) int main() { scanf("%s",s1+1);//从1开始存,个人习惯 n=re(); len[0]=strlen(s1+1); _for(i,1,len[0])//分段 if(s1[i]=='*')//处理*和? hash1[++cnt]='*'; else if(s1[i]=='?') hash1[++cnt]='?'; else if(s1[i-1]<'a'||s1[i-1]>'z')//前面不是字母,记录长度 hash1[++cnt]=s1[i]-'a'+1,len[cnt]=1; else//前面是字母 hash1[cnt]=hash1[cnt]*131+s1[i]-'a'+1,len[cnt]++; hl=len[0]; p[0]=1;//Hash 131进制 _for(i,1,len[0]) p[i]=p[i-1]*131; while(n--) { scanf("%s",s2+1); len2=strlen(s2+1); _for(i,1,len2)//正常Hash hash2[i]=hash2[i-1]*131+s2[i]-'a'+1; memset(f,0,sizeof(f)); if(len2>hl)//小小的卡常 { _for(i,hl+1,len2) p[i]=p[i-1]*131; hl=len2; } f[0][0]=1;//初始化!!!只初始化(0,0) _for(i,1,cnt) { if(!len[i])//不是字母 { if(hash1[i]=='?') {//?是下一个字母任意 _for(j,0,len2)//由上一行向下转移 if(f[i-1][j]) f[i][j+1]=1; } else {//*是之后的字母全任意 _for(j,0,len2) if(f[i-1][j]) { _for(k,j,len2) f[i][k]=1; break; } if(f[i-1][0]) f[i][0]=1; } continue; } _for(j,len[i],len2)//正常字符串匹配 if(hash1[i]==hash2[j]-hash2[j-len[i]]*p[len[i]]&&f[i-1][j-len[i]]) //一定是要能转移过来的 f[i][j]=1; } if(f[cnt][len2])//要求是完全匹配,所以只看放完最后一组最后一位是否能放 printf("YES\n"); else printf("NO\n"); } return 0; } /* 观察题目,通配符不超过10个 分段 Hash 跑DP 类似[TJOI2018]碱基序列 */