您的位置:首页 > 理论基础 > 数据结构算法

HDU 4436 后缀数组

2016-10-06 20:55 337 查看
点击打开链接

题意:给n个串,求所有的子串去重后相加对2012取余的值

思路:思路借鉴这篇博客,其中有一个求一段串可以形成的和有点类似与字符串hash的想法,用的很巧,要用后缀数组的话不同两个串的连接需要用一个其他的数字,然后正常计算sa和height,然后当遇到的第i个是加的那个数字或者是0都不计算,因为题目说前导不能为0,然后i+height[Rank[i]]要小于i所在的串的结束位置,然后计算的式子就是要加的结果,画一画样例就好理解了#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int MAXN=200010;
const int mod=2012;
int sa[MAXN];
int t1[MAXN],t2[MAXN],c[MAXN];
int Rank[MAXN],height[MAXN];
void construct_sa(int 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(int s[],int n){
int k=0;
for(int i=0;i<=n;i++) Rank[sa[i]]=i;
for(int i=0;i<n;i++){
if(k)k--;
int j=sa[Rank[i]-1];
while(s[i+k]==s[j+k])k++;
height[Rank[i]]=k;
}
}
int s[MAXN],id[MAXN],sum[MAXN],T[MAXN],V[MAXN],base[MAXN],arrive[MAXN];
char str[MAXN];
int calc_sum(int l,int r){
int ans=T[r+1]-T[l];
ans%=mod;ans-=V[l]*base[r-l+1];
ans=(ans+mod)%mod;
if(ans<0) ans+=mod;
return ans;
}
int main(){
base[1]=10;for(int i=2;i<MAXN;i++) base[i]=(base[i-1]+1)*10%mod;
int n;
while(scanf("%d",&n)!=-1){
int k=0,val=0;
for(int i=1;i<=n;i++){
scanf("%s",str);
int len=strlen(str);
for(int j=0;j<len;j++){
s[k]=str[j]-'0'+1;
val=(val*10+s[k]-1)%mod;
V[k+1]=val;
T[k+1]=(T[k]+val)%mod;
id[k]=i;k++;
}
s[k]=11;
val=(val*10+10)%mod;
V[k+1]=val;
T[k+1]=(T[k]+val)%mod;
id[k]=i;k++;arrive[i]=k-2;
}
s[k]=0;
construct_sa(s,k+1,128);
construct_lcp(s,k);
int ans=0;
for(int i=0;i<k;i++){
if(s[i]%10!=1){
if(i+height[Rank[i]]<=arrive[id[i]]){//小于这个界限才会有不重复的串
ans+=calc_sum(i,arrive[id[i]])-calc_sum(i,i+height[Rank[i]]-1);
ans=(ans+mod)%mod;
if(ans<0) ans+=mod;
}
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息