听上去像是破坏植物的暴力行为(并不)。
可以快速查询某个字符串在某个字符串集中出现了几次,而且听上去比字符串哈希靠谱。
把整个字符串集建成树,边权是字符,对于字符串结尾的节点进行特殊标记。
这样一方面合并了前缀,节省空间;另一方面查询很方便,直接按边走就行。
#include<iostream> #include<iomanip> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define maxn 10010 #define maxk maxn*50 #define maxm 30 #define maxb 110010 using namespace std; int read(){ int f=1,x=0;char ch=getchar(); while(isdigit(ch)==0 && ch!='-')ch=getchar(); if(ch=='-')f=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } void write(int x){ int ff=0;char ch[15]; while(x)ch[++ff]=(x%10)+'0',x/=10; if(ff==0)putchar('0'); while(ff)putchar(ch[ff--]); putchar(' '); } struct AC{ int cnt,len,to[maxk][maxm],n,val[maxk],m; bool yes[maxk]; char s[60]; int getnum(char c){ return int(c-'a'); } void build(){ int u=0,cur=0; for(;u<len;u++){ if(!to[cur][getnum(s[u])]) to[cur][getnum(s[u])]=++cnt; cur=to[cur][getnum(s[u])]; } val[cur]++,yes[cur]=1; return ; } void getans(){ int u=0,cur=0; for(;u<len;u++){ if(!to[cur][getnum(s[u])]) {printf("WRONG ");return;} cur=to[cur][getnum(s[u])]; } if(yes[cur]==0)printf("WRONG "); else if(val[cur]==0)printf("REPEAT "); else {val[cur]--;printf("OK ");} return; } void prt(){ for(int i=0;i<=cnt;i++){ for(int j=0;j<=25;j++){ write(to[i][j]); } cout<<endl; } } void init(){ cnt=0; n=read(); for(int i=1;i<=n;i++){ scanf("%s",s); len=strlen(s); build(); } // prt(); } void ask(){ m=read(); for(int i=1;i<=m;i++){ scanf("%s",s); len=strlen(s); getans(); } } }solve; int main(){ solve.init(); solve.ask(); return 0; }
其实这是AC代码
知道了这些又有什么用呢?某些字符串问题就能在树上乱搞了。