[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 }