Bzoj3230 相似子串

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1783  Solved: 444
[Submit][Status][Discuss]

Description

 

Input

输入第1行,包含3个整数N,Q。Q代表询问组数。
第2行是字符串S。
接下来Q行,每行两个整数i和j。(1≤i≤j)。

 

Output

输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。

 

Sample Input

5 3
ababa
3 5
5 9
8 10

Sample Output

18
16
-1

HINT

 

样例解释

第1组询问:两个子串是“aba”,“ababa”。f = 32 + 32 = 18。

第2组询问:两个子串是“ababa”,“baba”。f = 02 + 42 = 16。

第3组询问:不存在第10个子串。输出-1。


数据范围

N≤100000,Q≤100000,字符串只由小写字母'a'~'z'组成

 

 

字符串 后缀数组 ST表

哇,我可能是写了假的ST表,下标错了一位,WA到飞起

 

先算出后缀数组,然后按rank递增顺序维护本质不同的子串的数量的前缀和(显然rank为i的串长度减去height[i]就是这个串贡献出的不同子串数量),然后可以在前缀和数组上二分,找到第X个本质不同子串的起点所在的后缀的rank(好绕口),记为id。那么目标串的起点就是sa[id],终点就是 sa[id]+height[id]-1+(X-sum[id-1])。

成功对两个目标串定位以后,分别求最长公共前缀和后缀长度,它们平方的和就是答案

 

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #define LL long long
  7 using namespace std;
  8 const int mxn=100010;
  9 LL read(){
 10     LL x=0,f=1;char ch=getchar();
 11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 13     return x*f;
 14 }
 15 int sa[mxn],rk[mxn],ht[mxn],r[mxn];
 16 LL smm[mxn];
 17 int wa[mxn],wb[mxn],wv[mxn],cnt[mxn];
 18 inline int cmp(int *r,int a,int b,int l){
 19     return r[a]==r[b] && r[a+l]==r[b+l];
 20 }
 21 void GetSA(int *sa,int n,int m){
 22     int *x=wa,*y=wb;
 23     int i,j,p;
 24     for(i=0;i<m;i++)cnt[i]=0;
 25     for(i=0;i<n;i++)cnt[x[i]=r[i]]++;
 26     for(i=1;i<m;i++)cnt[i]+=cnt[i-1];
 27     for(i=n-1;i>=0;i--)sa[--cnt[x[i]]]=i;
 28     for(j=1,p=0;p<n;j<<=1,m=p){
 29         p=0;for(i=n-j;i<n;i++)y[p++]=i;
 30         for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
 31         for(i=0;i<m;i++)cnt[i]=0;
 32         for(i=0;i<n;i++)++cnt[x[y[i]]];
 33         for(i=1;i<m;i++)cnt[i]+=cnt[i-1];
 34         for(i=n-1;i>=0;i--)sa[--cnt[x[y[i]]]]=y[i];
 35         swap(x,y);
 36         p=1;x[sa[0]]=0;
 37         for(i=1;i<n;i++)
 38             x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
 39     }
 40     return;
 41 }
 42 void GetHT(int n){
 43     int i,j,k=0;
 44     for(i=1;i<=n;i++)rk[sa[i]]=i;
 45     for(i=0;i<n;i++){
 46         if(k)k--;
 47         j=sa[rk[i]-1];
 48         while(r[i+k]==r[j+k])k++;
 49         ht[rk[i]]=k;
 50     }
 51     smm[0]=0;
 52     for(i=1;i<=n;i++)smm[i]=smm[i-1]+n-sa[i]-ht[i];
 53     return;
 54 }
 55 int f[mxn][18],lg[mxn];
 56 int n,Q;
 57 void ST_init(){
 58     for(int i=1;i<=n;i++)f[i][0]=ht[i];
 59     for(int j=1;j<18;j++)
 60         for(int i=1;i<=n;i++){
 61             if(i+(1<<j)-1>n)break;
 62             f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
 63         }
 64     return;
 65 }
 66 int ST(int x,int y){
 67     if(x>y)swap(x,y);++x;
 68     int tmp=lg[y-x+1];
 69     return min(f[x][tmp],f[y-(1<<tmp)+1][tmp]);
 70 }
 71 struct QUE{
 72     LL x,y;
 73     int s1,t1,s2,t2;
 74 }q[mxn];
 75 LL A[mxn][2];
 76 int calc(LL x,LL y,int ID){
 77     int id=lower_bound(smm+1,smm+n+1,x)-smm;
 78     int s1=sa[id];
 79     int t1=s1+(LL)ht[id]-1+x-smm[id-1];
 80     id=lower_bound(smm+1,smm+n+1,y)-smm;
 81     int s2=sa[id];
 82     int t2=s2+(LL)ht[id]-1+y-smm[id-1];
 83     q[ID].s1=s1;q[ID].t1=t1;q[ID].s2=s2;q[ID].t2=t2;
 84     int res=min(t1-s1+1,t2-s2+1);
 85     if(s1!=s2)res=min(res,ST(rk[s1],rk[s2]));//printf("res:%d\n",res);
 86     return res;
 87 }
 88 int calc2(int ID){
 89     int s1=q[ID].s1;int t1=q[ID].t1;
 90     int s2=q[ID].s2;int t2=q[ID].t2;
 91     int res=min(t1-s1+1,t2-s2+1);
 92     if(s1!=s2)res=min(res,ST(rk[s1],rk[s2]));//printf("res:%d\n",res);
 93     return res;    
 94 }
 95 void solve(int id){
 96     GetSA(sa,n+1,28);
 97     GetHT(n);
 98     ST_init();
 99     for(int i=1;i<=Q;i++){
100         if(q[i].x>0 && q[i].x<=smm[n] && q[i].y>0 && q[i].y<=smm[n]){
101 //        if(q[i].x<=smm[n] && q[i].y<=smm[n]){
102             if(!id)A[i][id]=calc(q[i].x,q[i].y,i);
103             else A[i][id]=calc2(i);
104         }
105         else A[i][id]=-1;
106     }
107     return;
108 }
109 char s[mxn];
110 int main(){
111 //    freopen("in.txt","r",stdin);
112     int i,j;
113     n=read();Q=read();
114     scanf("%s",s);
115     for(i=1;i<=Q;i++){
116         q[i].x=read();q[i].y=read();
117     }
118     lg[0]=-1;
119     for(i=1;i<=n;i++)lg[i]=lg[i>>1]+1;
120     for(i=0;i<n;i++)r[i]=s[i]-'a'+1;
121     solve(0);
122     reverse(r,r+n);
123     for(i=1;i<=Q;i++){
124         q[i].s1=n-q[i].s1-1;q[i].s2=n-q[i].s2-1;
125         q[i].t1=n-q[i].t1-1;q[i].t2=n-q[i].t2-1;
126         swap(q[i].s1,q[i].t1);swap(q[i].s2,q[i].t2);
127     }
128     solve(1);
129     for(i=1;i<=Q;i++){
130         if(A[i][0]==-1)printf("-1\n");
131         else printf("%lld\n",(LL)A[i][0]*A[i][0]+(LL)A[i][1]*A[i][1]); 
132     }
133     return 0;
134 }

 

 

 

 

转载于:https://www.cnblogs.com/SilverNebula/p/6912092.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值