在网络赛期间罢赛不做题了过来写博客真是一种罪过,然而被零封实在是没有勇气坚持最后一个小时。。。。
两个队友都不在,单挑太水了
————————————————————————————————————————————————————————
进入正题
模版上述地方有,根据题目对自己的理解进行解释:
题意:给定m和l和一个字符串,
求该串中连续m个长为l的子串互不重复的数目
char s[maxn]; ull base[maxn],Hash[maxn]; map<ull,int> mp; int main(){ //input; int m,l,i,len,ans; base[0]=1; for(i=1;i<maxn;i++) base[i]=base[i-1]*seed; while(scanf("%d%d",&m,&l)!=EOF){ scanf("%s",s); ans=0; len=strlen(s); Hash[len]=0; for(i=len-1;i>=0;i--) Hash[i]=Hash[i+1]*seed+s[i]-'a'; for(i=0;i<l&&i+m*l<len;i++){//枚举以i位置为起点,长度为m*l的子串是否合法 mp.clear(); for(int j=i;j<i+m*l;j+=l){// ull temp=Hash[j]-Hash[j+l]*base[l]; mp[temp]++; } if (mp.size()==m) ans++; for(int j=i+m*l;j+l<=len;j+=l){//更换起点,i+km为起点依次往后推 ull temp=Hash[j-m*l]-Hash[j-(m-1)*l]*base[l]; mp[temp]--; if (!mp[temp]) mp.erase(temp); temp=Hash[j]-Hash[j+l]*base[l]; mp[temp]++; if (mp.size()==m) ans++; } } printf("%d\n",ans); } return 0; }
/* 字符串题目注意: Hash,Rank这类单词一定首字母大写,不然CE 题意:给定一个字符串和出现次数k, 找出至少出现k次的最长的子串长度以及其最后一次出现的位置(首字符的位置) 二分判断某个长度是否可行,找到最大的。。。。 按照哈希值的大小排序:越大的位数“相对” 越长 */ int l,len,pos,Rank[maxn]; ull Hash[maxn],xp[maxn],haha[maxn]; char str[maxn]; bool cmp(int a,int b){ /*if (haha[a]==haha[b]) return a<b; return haha[a]<haha[b];*/ return (haha[a]!=haha[b])?(haha[a]<haha[b]):(a<b); } bool solve(int mid){ int c=1; pos=-1; for(int i=0;i<len-mid+1;i++){ Rank[i]=i; haha[i]=Hash[i]-Hash[i+mid]*xp[mid]; } sort(Rank,Rank+len-mid+1,cmp); //注意第二个参数,len-mid+1描述的是数组中元素个数 //开始找 for(int i=0;i<len-mid+1;i++){ if (i==0||haha[Rank[i]]!=haha[Rank[i-1]]) c=1; else{ c++; if (c>=l) pos=max(pos,Rank[i]); } } return pos>=0; } int main(){ //input; while(scanf("%d",&l)!=EOF){ if (!l) break; scanf("%s",str); len=strlen(str); if (l==1){//特判,串长为1 printf("%d %d\n",len,0); continue; } memset(Hash,0,sizeof(Hash)); memset(xp,0,sizeof(xp)); xp[0]=1; for(int i=len-1;i>=0;i--) Hash[i]=Hash[i+1]*x+str[i]-'a'; for(int i=1;i<len;i++) xp[i]=xp[i-1]*x; if (!solve(1)){//又是细节判断,无解输出 puts("none"); continue; } int low=1,high=len,mid; while(low+1<high){ mid=(low+high)>>1; if (solve(mid)) low=mid; else high=mid; } solve(low); printf("%d %d\n",low,pos); } return 0; }
我bin带你飞的专题直接刷爆把:练习KMP
看过算法之后,学学我bin神的模板保证比赛平安:
HDOJ 2222
struct Trie{ int next[500010][26],fail[500010],end[500010]; int root,L; int newnode(){ for(int i=0;i<26;i++) next[L][i]=-1; end[L++]=0; return L-1; } void init(){ L=0; root=newnode(); } void insert(char buf[]){ int len=strlen(buf); int now=root; for(int i=0;i<len;i++){ if (next[now][buf[i]-'a']==-1) next[now][buf[i]-'a']=newnode(); now=next[now][buf[i]-'a']; } end[now]++; } void build(){ queue<int> Q; fail[root]=root; for(int i=0;i<26;i++) if (next[root][i]==-1) next[root][i]=root; else{ fail[next[root][i]]=root; Q.push(next[root][i]); } while(!Q.empty()){ int now=Q.front(); Q.pop(); for(int i=0;i<26;i++) if (next[now][i]==-1) next[now][i]=next[fail[now]][i]; else{ fail[next[now][i]]=next[fail[now]][i]; Q.push(next[now][i]); } } } int query(char buf[]){ int len=strlen(buf); int now=root; int res=0; for(int i=0;i<len;i++){ now=next[now][buf[i]-'a']; int temp=now; while(temp!=root){ res+=end[temp]; end[temp]=0; temp=fail[temp]; } } return res; } }; char buf[1000010]; Trie ac; int main(){ //input; int T,n; scanf("%d",&T); while(T--){ scanf("%d",&n); ac.init(); for(int i=0;i<n;i++){ scanf("%s",buf); ac.insert(buf); } ac.build(); scanf("%s",buf); printf("%d\n",ac.query(buf)); } return 0; }
习题链接:我bin带你飞——AC自动机专题
第一题HDOJ2222模板题
第二题HDOJ2896需要改动模板:对end数组中记录各个字符串的编号
第三题HDOJ3065需要改动模板:每个字符串在模式串之中匹配了几次(在query中添加一个标记数组)
第四题ZOJ3430需要添加一个base64的解码算法。。。弱写了太久,还是WA,直接搬运我bin的吧:
unsigned char buf[2050]; int tot; char str[4000]; unsigned char s[4000]; unsigned char Get(char ch) { if( ch>='A'&&ch<='Z' )return ch-'A'; if( ch>='a'&&ch<='z' )return ch-'a'+26; if( ch>='0'&&ch<='9' )return ch-'0'+52; if( ch=='+' )return 62; else return 63; } void change(unsigned char str[],int len) { int t=0; for(int i=0;i<len;i+=4) { buf[t++]=((str[i]<<2)|(str[i+1]>>4)); if(i+2 < len) buf[t++]=( (str[i+1]<<4)|(str[i+2]>>2) ); if(i+3 < len) buf[t++]= ( (str[i+2]<<6)|str[i+3] ); } tot=t; } main(): int n,m; while(scanf("%d",&n) == 1) { ac.init(); for(int i = 0;i < n;i++) { scanf("%s",str); int len = strlen(str); while(str[len-1]=='=')len--; for(int j = 0;j < len;j++) { s[j] = Get(str[j]); } change(s,len); ac.insert(buf,tot,i); }