HDU5769后缀数组,高度数组模板
来源:互联网 发布:陆逊 知乎 编辑:程序博客网 时间:2024/06/11 03:43
首先学一波字符串的一些性质。首先求出字符串的后缀数组和高度数组之后,就可以求出这个字符串有多少个不同的字串。
PS:这个后缀数组模板为倍增+基数排序。复杂度nlog(n),基数排序O(n),倍增是log但是常数太大,.高度数组可以利用后缀数组O(n)求出!
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int inf=0x3f3f3f3f;const int MAXN=100010;int sa[MAXN];int t1[MAXN],t2[MAXN],c[MAXN];int Rank[MAXN],lcp[MAXN];void construct_sa(char s[],int n,int m){ int i,j,p,*x=t1,*y=t2; for(i=0;i<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[i]=s[i]]++; for(i=1;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; for(j=1;j<=n;j<<=1){ p=0; for(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<m;i++)c[i]=0; for(i=0;i<n;i++)c[x[y[i]]]++; for(i=1;i<m;i++)c[i]+=c[i-1]; for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++; if(p>=n)break; m=p; }}void construct_lcp(char s[],int n){ int h=0;lcp[0]=0; for(int i=0;i<=n;i++) Rank[sa[i]]=i; for(int i=0;i<n;i++){ if(h>0)h--; int j=sa[Rank[i]-1]; for(;j+h<n&&i+h<n;h++) { if(s[j+h]!=s[i+h]) break; } lcp[Rank[i]]=h; }}int fvis[MAXN],pr[MAXN];char str[MAXN];int main(){ int T,cas=1; char ch[10]; scanf("%d",&T); while(T--){ scanf("%s",ch); scanf("%s",str); int n=strlen(str),flag=0,fpr; memset(fvis,0,sizeof(fvis)); memset(pr,0,sizeof(pr)); for(int i=n-1;i>=0;i--){ if(str[i]==ch[0]){ flag=1;fpr=i; } if(flag) fvis[i]=1,pr[i]=fpr; } ll ans=0; construct_sa(str,n+1,128); construct_lcp(str,n); for(int i=0;i<=n;i++){ if(fvis[sa[i]]) ans=ans+n-max((sa[i]+lcp[i]),pr[sa[i]]); } printf("Case #%d: %I64d\n",cas++,ans); } return 0;}
下面这个是nlog(n)log(n)的模板,做这个题就超时了,利用的是倍增的思想,但是是普通的排序,(nlog(n)).
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int inf=0x3f3f3f3f;const int MAXN=100010;int sa[MAXN];int nn;int kk;int Rank[MAXN],lcp[MAXN],tmp[MAXN];bool compare_sa(int i,int j){ if(Rank[i]!=Rank[j]) return Rank[i]<Rank[j]; else { int ri=i+kk<=nn?Rank[i+kk]:-1; int rj=j+kk<=nn?Rank[j+kk]:-1; return ri<rj; }}void construct_sa(char s[],int n){ for(int i=0;i<=n;i++) { sa[i]=i; Rank[i]=i<n?sa[i]:-1; } for(kk=1;kk<=n;kk*=2) sort(sa,sa+n+1,compare_sa); tmp[sa[0]]=0; for(int i=1;i<=n;i++) { tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0); } for(int i=0;i<=n;i++) { Rank[i]=tmp[i]; }}void construct_lcp(char s[],int n){ int h=0;lcp[0]=0; for(int i=0;i<=n;i++) Rank[sa[i]]=i; for(int i=0;i<n;i++){ if(h>0)h--; int j=sa[Rank[i]-1]; for(;j+h<n&&i+h<n;h++) { if(s[j+h]!=s[i+h]) break; } lcp[Rank[i]]=h; }}int fvis[MAXN],pr[MAXN];char str[MAXN];int main(){ int T,cas=1; char ch[10]; scanf("%d",&T); while(T--){ scanf("%s",ch); scanf("%s",str); int n=strlen(str),flag=0,fpr; memset(fvis,0,sizeof(fvis)); memset(pr,0,sizeof(pr)); for(int i=n-1;i>=0;i--){ if(str[i]==ch[0]){ flag=1;fpr=i; } if(flag) fvis[i]=1,pr[i]=fpr; } ll ans=0; nn=n+1; construct_sa(str,n+1); construct_lcp(str,n); for(int i=0;i<=n;i++){ if(fvis[sa[i]]) ans=ans+n-max((sa[i]+lcp[i]),pr[sa[i]]); } printf("Case #%d: %I64d\n",cas++,ans); } return 0;}
阅读全文
1 0
- HDU5769后缀数组,高度数组模板
- HDU5769之后缀数组
- HDU5769 Substring 后缀数组
- HDU5769后缀数组的简单应用
- 后缀数组,高度数组
- (多校第四场1006)HDU5769 Substring 后缀数组
- 后缀数组和高度数组 模板及应用
- 【后缀数组】后缀数组模板
- 后缀数组之高度数组
- 后缀数组【模板】
- 【后缀数组模板】
- 后缀数组模板
- 后缀数组模板
- 【模板】后缀数组
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 【省选】【后缀数组】模板
- if语句的套路:
- JavaScript的程序设计思维与选择结构
- 欢迎使用CSDN-markdown编辑器
- linux下jdk版本切换
- 程序设计思维
- HDU5769后缀数组,高度数组模板
- 关于margin与padding设置百分比的问题
- 下拉刷新——Android使用SwipeRefreshLayout简单实现下拉刷新与加载跟多
- opencv 高斯滤波
- Hadoop-入门-01
- JavaScript学习小结(2)
- console.log()用法
- 贪心算法-nyoj-91-阶乘之和
- 嵌入式系统学习——S3C2451之RTC时钟