Hdu 4552 怪盗基德的挑战书 (所有前缀出现次数和 后缀数组或KMP)
2014-07-06 20:21
363 查看
题意:所有前缀出现次数和
之前用kmp写过类似的题,这次尝试用后缀数组写一下。
求出每个后缀和最长的后缀的公共前缀长度就可以了,最长的后缀是字符串本身,也就是rank[0],所以在Height数组中从rank[0]的位置往两边找即可
后面附两份KMP的。
之前用kmp写过类似的题,这次尝试用后缀数组写一下。
求出每个后缀和最长的后缀的公共前缀长度就可以了,最长的后缀是字符串本身,也就是rank[0],所以在Height数组中从rank[0]的位置往两边找即可
后面附两份KMP的。
#include <cstdio> #include <cstring> #include <algorithm> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) const int N = int(1e5)+10; int cmp(int *r,int a,int b,int l){ return (r[a]==r[b]) && (r[a+l]==r[b+l]); } int wa ,wb ,ws ,wv ; int rank ,height ,sa ; void DA(int *r,int *sa,int n,int m){ int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) ws[i]=0; for(i=0;i<n;i++) ws[x[i]=r[i]]++; for(i=1;i<m;i++) ws[i]+=ws[i-1]; for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p){ for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) ws[i]=0; for(i=0;i<n;i++) ws[wv[i]]++; for(i=1;i<m;i++) ws[i]+=ws[i-1]; for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; //printf("p = %d\n", p ); } } void calheight(int *r,int *sa,int n){ // memset(height,0,sizeof(height)); // memset(rank,0,sizeof(rank)); int i,j,k=0; for(i=1;i<=n;i++) rank[sa[i]]=i; for(i=0;i<n; height[rank[i++]] = k ) for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++); } char str ; int data ; int main () { while (~scanf("%s",str)) { int n=strlen(str); for (int i=0;i<=n;i++) data[i]=str[i]; DA(data,sa,n+1,128); calheight(data,sa,n); int ans=n; int t=rank[0]; int tmp=n; while (t<n) { tmp=min(tmp,height[t+1]); t++; ans+=tmp; } t=rank[0]; tmp=n; while(t>1) { tmp=min(tmp,height[t]); t--; ans+=tmp; } printf("%d\n",ans%256); } return 0; }
#include <cstdio> #include <cstring> const int N=100005; char str ; int next ,cnt ,n,sum; void getNext (char s[],int len) { next[0]=-1; int i=0,j=-1; while (i<len) { if (j==-1 || s[i]==s[j]) next[++i]=++j; else j=next[j]; } } void KMP () { int i=0,j=0; while (i<n) if (j == -1 || str[i] == str[j]) i++,j++,cnt[j]++; else j=next[j]; for (i=n;i>0;i--) //统计每个前缀出现次数,cnt[i]表示长度为i的前缀出现了cnt[i]次 if (next[i] != -1) { cnt[next[i]] =(cnt[next[i]]+cnt[i])%256; sum=(sum+cnt[i])%256; } } int main () { while (~scanf("%s",str)) { sum=0; n=strlen(str); memset(cnt,0,sizeof(cnt)); getNext(str,n); KMP(); printf("%d\n",sum); } return 0; }
#include <cstdio> #include <cstring> const int MOD=256; const int N=100005; char s ; int next ,n,f ; void getNext(char s[],int len) { next[0]=-1; int i=0,j=-1; while (i<len) { if (j==-1 || s[i]==s[j]) next[++i]=++j; else j=next[j]; } } int DP () { int ans=0; memset(f,0,sizeof(f)); for (int i=1;i<=n;i++) {//f[i]表示长度为i的字符串(也就是把str[i]当成'\0')总共含前缀的数量 f[i]=f[next[i]]+1;//+1表示长度为next[i]的前缀在当前结尾又出现了一次 ans=(ans+f[i])%MOD; } return ans; } int main () { while (~scanf("%s",s)) { n=strlen(s); getNext(s,n); printf("%d\n",DP()); } return 0; }
相关文章推荐
- hdoj 4552 怪盗基德的挑战书 【KMP 求所有前缀在原串种出现的次数之和】
- hdu 4552 求所有字符串前缀在字符串中出现的总次数
- HDU 3336 KMP 求所有前缀在母串中出现的次数
- hdoj 4552 怪盗基德的挑战书【求前缀在字符串中出现的次数之和】
- 【HDU 4552】怪盗基德的挑战书(kmp)
- hdu4552怪盗基德的挑战书 --KMP求字符串所有的前缀数
- HDU 4552 怪盗基德的挑战书 (KMP + DP) 或 后缀数组
- HDU 1358 KMP运用 求某串中所有循环前缀串的长度和循环次数
- 【HDU 4552】怪盗基德的挑战书 【KMP next数组的巧妙应用】
- hdoj 3336 Count the string 【kmp求 所有前缀 在原串中出现的次数 总和】
- HDU 4552 怪盗基德的挑战书(kmp+dp)
- hdu 3336Count the string(KMP变形,求前缀出现的次数和)
- HDU-4552 怪盗基德的挑战书 KMP | 后缀数组 | 暴力
- HDU 3336 Count the string 所有前缀在串中的出现总次数
- 怪盗基德的挑战书 HDU - 4552 (kmp思维)
- hdu 4552 怪盗基德的挑战书【KMP+dp || 优雅暴力】
- Hdu 3336 Count the string (KMP+DP 前缀出现次数和)
- HDU - 4552 怪盗基德的挑战书 (后缀数组)
- HDU 3336 Count the string (KMP next数组运用——统计前缀出现次数)
- HDU 4552 怪盗基德的挑战书(后缀数组)