[HAOI2016]找相同字符

题目描述

给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。

输入输出格式

输入格式:

两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母

输出格式:

输出一个整数表示答案

输入输出样例

输入样例#1: 复制
aabb
bbaa
输出样例#1: 复制
10
将两串合并,中间加一个分隔符
先求出后缀数组和LCP的height数组
要求的就是后缀数组中不属于同一串的后缀的LCP
对于每一个(l,r)找到最小值位置minpos
在两边找来自两个不同串后缀数,分两种情况统计
然后分两边(l,minpos-1),(minpos,r)
用线段树维护
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 typedef long long lol;
  9 struct Seg
 10 {
 11   lol cnt[3];
 12   int x,pos;
 13 }t[2000001];
 14 struct Data
 15 {
 16   int l,r;
 17 };
 18 int SA[500001],c[500001],rank[500001],x[500001],y[500001],len1,len2,n,m,s[500001];
 19 char s1[500001],s2[500001];
 20 queue<Data>Q;
 21 lol ans,h[500001];
 22 void build(int rt,int l,int r)
 23 {
 24   if (l==r)
 25     {
 26       if (SA[l]<len1) t[rt].cnt[1]=1;
 27       if (SA[l]>len1) t[rt].cnt[2]=1;
 28       t[rt].x=h[l];
 29       t[rt].pos=l;
 30       return;
 31     }
 32   int mid=(l+r)>>1;
 33   build(rt<<1,l,mid);
 34   build(rt<<1|1,mid+1,r);
 35   t[rt].cnt[1]=t[rt<<1].cnt[1]+t[rt<<1|1].cnt[1];
 36   t[rt].cnt[2]=t[rt<<1].cnt[2]+t[rt<<1|1].cnt[2];
 37   if (t[rt<<1].x<=t[rt<<1|1].x)
 38     {
 39       t[rt].pos=t[rt<<1].pos;
 40       t[rt].x=t[rt<<1].x;
 41     }
 42   else
 43     {
 44       t[rt].pos=t[rt<<1|1].pos;
 45       t[rt].x=t[rt<<1|1].x;
 46     }
 47 }
 48 lol query_cnt(int rt,int l,int r,int L,int R,int x)
 49 {
 50   if (l>=L&&r<=R)
 51     {
 52       return t[rt].cnt[x];
 53     }
 54   int mid=(l+r)>>1;
 55   lol s=0;
 56   if (L<=mid) s+=query_cnt(rt<<1,l,mid,L,R,x);
 57   if (R>mid) s+=query_cnt(rt<<1|1,mid+1,r,L,R,x);
 58   return s;
 59 }
 60 int query_min(int rt,int l,int r,int L,int R)
 61 {
 62   if (l>=L&&r<=R)
 63     {
 64       return t[rt].pos;
 65     }
 66   int mid=(l+r)>>1,s1=-1,s2=-1;
 67   if (L<=mid) s1=query_min(rt<<1,l,mid,L,R);
 68   if (R>mid) s2=query_min(rt<<1|1,mid+1,r,L,R);
 69   if (s2==-1) return s1;
 70   if (s1==-1) return s2;
 71   if (h[s2]>=h[s1]) return s1;
 72   return s2;
 73 }
 74 void radix_sort()
 75 {int i;
 76   for (i=0;i<m;i++)
 77     c[i]=0;
 78   for (i=0;i<n;i++)
 79     c[x[y[i]]]++;
 80   for (i=1;i<m;i++)
 81     c[i]+=c[i-1];
 82   for (i=n-1;i>=0;i--)
 83     SA[--c[x[y[i]]]]=y[i];
 84 }
 85 void build_SA()
 86 {int i,j,k,p;
 87   for (i=0;i<n;i++)
 88     x[i]=s[i],y[i]=i;
 89   m=1000;
 90   radix_sort();
 91   for (k=1;k<=n;k<<=1)
 92     {
 93       p=0;
 94       for (i=n-k;i<n;i++)
 95     y[p++]=i;
 96       for (i=0;i<n;i++)
 97     if (SA[i]>=k) y[p++]=SA[i]-k;
 98       radix_sort();
 99       p=1;
100       swap(x,y);
101       x[SA[0]]=0;
102       for (i=1;i<n;i++)
103     x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&((SA[i]+k<n?y[SA[i]+k]:-1)==(SA[i-1]+k<n?y[SA[i-1]+k]:-1)))?p-1:p++;
104       if (p>=n) break;
105       m=p;
106     }
107   for (i=0;i<n;i++)
108     rank[SA[i]]=i;
109   int L=0;
110   for (i=0;i<n;i++)
111     if (rank[i]>0)
112       {
113     if (L>0) L--;
114     j=SA[rank[i]-1];
115     while (i+L<n&&j+L<n&&(s[i+L]==s[j+L])) L++;
116     h[rank[i]]=L;
117       }
118 }
119 int main()
120 {int i;
121   cin>>s1>>s2;
122   len1=strlen(s1),len2=strlen(s2);
123   for (i=0;i<len1;i++)
124     s[i]=(int)s1[i];
125   s[len1]=(int)'#';
126   for (i=0;i<len2;i++)
127     s[i+len1+1]=(int)s2[i];
128   n=len1+len2+1;
129   build_SA();
130   build(1,0,n-1);
131   Q.push((Data){0,n-1});
132   while (Q.empty()==0)
133     {
134       Data u=Q.front();
135       Q.pop();
136       int l=u.l,r=u.r;
137       int minpos=query_min(1,0,n-1,l+1,r);
138       //cout<<l<<' '<<r<<' '<<h[minpos]<<endl;
139       if (l<minpos-1) Q.push((Data){l,minpos-1});
140       if (minpos<r) Q.push((Data){minpos,r});
141       ans+=query_cnt(1,0,n-1,l,minpos-1,1)*query_cnt(1,0,n-1,minpos,r,2)*h[minpos];
142       ans+=query_cnt(1,0,n-1,l,minpos-1,2)*query_cnt(1,0,n-1,minpos,r,1)*h[minpos];
143     }
144   cout<<ans;
145 }

 

posted @ 2018-02-27 10:55  Z-Y-Y-S  阅读(206)  评论(0编辑  收藏  举报