Bzoj4566 [Haoi2016]找相同字符
2017-03-29 11:57
363 查看
Submit: 413 Solved: 224
Description
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两 个子串中有一个位置不同。
Input
两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
Output
输出一个整数表示答案
Sample Input
aabbbbaa
Sample Output
10HINT
Source
字符串 后缀数组
后缀自动机解法:http://www.cnblogs.com/SilverNebula/p/6562205.html
别人:听说这题可以用后缀自动机秒,但是我不会后缀自动机只好用后缀数组写了好麻烦呀
我:我知道这题可以用后缀自动机秒,但是我死活学不会后缀数组啊
(黑人问号.jpg)
研究了一上午后缀数组,试着写了一发,最后靠着标准代码比对可算是A了
把两个串拼在一起,中间用个大编码字符隔开,结尾加个0编码字符,建立后缀数组。
一个暴力的算法是在rank数组中枚举起点,然后往后一直扫到串尾,过程中维护最小height,如果扫到一个串和起点不在同一个串中,答案+=当前height
发现答案主要和height有关,于是把后缀串按height从大到小排序,依次添加进一个集合,依据先前添加进集合的两个串的子串数量(先添加进的height更大,所以当前对之前的有贡献),用乘法原理算答案。
参考了这里:http://blog.csdn.net/fzhvampire/article/details/51674402
/*by SilverN*/ #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> using namespace std; const int mxn=400105; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int sa[mxn],rk[mxn],ht[mxn],r[mxn]; int cnt[mxn],wa[mxn],wb[mxn],wv[mxn]; inline int cmp(int *r,int a,int b,int l){ return r[a]==r[b] && r[a+l]==r[b+l]; } void GetSA(int *sa,int *rk,int n,int m){ int i,j,p; int *x=wa,*y=wb; for(i=0;i<m;i++)cnt[i]=0; for(i=0;i<n;i++)cnt[x[i]=r[i]]++; for(i=1;i<m;i++)cnt[i]+=cnt[i-1]; for(i=n-1;i>=0;i--)sa[--cnt[x[i]]]=i; for(j=1,p=1;p<n;j<<=1,m=p){ for(p=0,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<n;i++)wv[i]=x[y[i]]; for(i=0;i<m;i++)cnt[i]=0; for(i=0;i<n;i++)cnt[wv[i]]++; for(i=1;i<m;i++)cnt[i]+=cnt[i-1]; for(i=n-1;i>=0;i--)sa[--cnt[wv[i]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(i=1;i<n;i++){ x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } } void GetHeight(int n){ int i,j,k=0; for(i=1;i<=n;i++)rk[sa[i]]=i; for(i=0;i<n;i++){ if(k)k--; j=sa[rk[i]-1]; while(r[i+k]==r[j+k])k++; ht[rk[i]]=k; } return; } int CMP(int a,int b){return ht[a]>ht[b];}//按height排序 int fa[mxn],id[mxn]; int st[mxn],ed[mxn],lim; int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } long long ans=0; void solve(int n){ int i,j; for(i=0;i<n;i++)id[i]=i,fa[i]=i; sort(id+1,id+n+1,CMP); for(i=0;i<n;i++){ if(sa[i]<lim)st[i]=1;// ed[i]=1-st[i]; } for(i=0;i<n;i++){ int now=id[i]; // printf("now:%d\n",id[i]); if(!now)continue; int x=find(now),y=find(now-1); ans+=(long long)(st[x]*ed[y]+st[y]*ed[x])*(long long)ht[now]; st[x]+=st[y]; ed[x]+=ed[y]; fa[y]=x; } printf("%lld\n",ans); return; } char s[mxn]; int main(){ int i,j; scanf("%s",s); int len=strlen(s); for(i=0;i<len;i++)r[i]=s[i]-'a'+1; r[len]=27;lim=len; scanf("%s",s); int l2=strlen(s); for(i=len+1;i<=l2+len;i++)r[i]=s[i-len-1]-'a'+1; len+=l2; r[++len]=0; //read GetSA(sa,rk,len+1,29); GetHeight(len); solve(len); /* printf("SA: "); for(i=1;i<=n;i++)printf("%d ",sa[i]); printf("\nrk: "); for(i=0;i<n;i++)printf("%d ",rk[i]); printf("\nht: "); for(i=0;i<n;i++)printf("%d ",ht[i]); printf("\nfin\n");*/ return 0; } /* aaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa asbbbbbbcccccccccaaaaaaaaaaaaaaaa 7139 */
相关文章推荐
- BZOJ 4566 [Haoi2016]找相同字符 后缀数组+ST表
- BZOJ 4566 [Haoi2016]找相同字符 ——广义后缀自动机
- BZOJ4566 [Haoi2016]找相同字符
- BZOJ 4566: [Haoi2016]找相同字符 后缀自动机
- [BZOJ4566][HAOI2016]找相同字符(SAM)
- [BZOJ4566][HAOI2016]找相同字符 后缀自动机
- BZOJ 4566: [Haoi2016]找相同字符
- 【bzoj4566】[Haoi2016]找相同字符
- BZOJ 4566: [Haoi2016]找相同字符
- 【bzoj4566】[Haoi2016]找相同字符
- bzoj 4566: [Haoi2016]找相同字符
- bzoj 4566: [Haoi2016]找相同字符
- bzoj 4566: [Haoi2016]找相同字符【SAM上DP
- 【BZOJ4566】【HAOI2016】找相同字符
- bzoj 4566: [Haoi2016]找相同字符 后缀自动机
- 【bzoj4566】[Haoi2016]找相同字符【后缀自动机】
- 【BZOJ4566】[Haoi2016]找相同字符 后缀数组+单调栈
- bzoj 4566: [Haoi2016]找相同字符
- BZOJ 4566: [Haoi2016]找相同字符 [后缀自动机]
- [bzoj4566][HAOI2016]找相同字符