国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > php教程 > bzoj4566【HAOI2016】找相同字符

bzoj4566【HAOI2016】找相同字符

来源:程序员人生   发布时间:2016-07-22 09:24:43 阅读次数:2812次

4566: [Haoi2016]找相同字符

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 128  Solved: 75
[Submit][Status][Discuss]

Description

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

Input

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

Output

输出1个整数表示答案

Sample Input

aabb
bbaa

Sample Output

10



广义后缀自动机

建立两个串的后缀自动机,统计1下每一个节点的两个串出现次数sz[i][0]和sz[i][1],则答案等于∑(mx[i]-mx[fa[i]])*sz[i][0]*sz[i][1]。

另外1个小细节就是拓扑排序的地方要注意1下。




#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define N 200005 #define M 800005 using namespace std; int n,m,cnt=1,last; int fa[M],mx[M],c[M][26],sz[M][2],v[N],q[M]; ll ans; char a[N],b[N]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=⑴;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int d[M]; queue<int> qu; void calc() { // F(i,1,cnt) v[mx[i]]++; // F(i,1,max(n,m)) v[i]+=v[i⑴]; // F(i,1,cnt) q[v[mx[i]]--]=i; //这样也是对的 int tmp=cnt; F(i,1,cnt) d[fa[i]]++; F(i,1,cnt) if (!d[i]) qu.push(i); while (!qu.empty()) { int x=qu.front();qu.pop(); q[tmp--]=x;d[fa[x]]--; if (!d[fa[x]]) qu.push(fa[x]); } D(i,cnt,1) { sz[fa[q[i]]][0]+=sz[q[i]][0]; sz[fa[q[i]]][1]+=sz[q[i]][1]; } F(i,1,cnt) ans+=(ll)(mx[i]-mx[fa[i]])*sz[i][0]*sz[i][1]; } void add(int x) { int p=last; if (c[p][x]&&mx[c[p][x]]==mx[p]+1){last=c[p][x];return;} int np=++cnt;last=np; mx[np]=mx[p]+1; while (p&&!c[p][x]) c[p][x]=np,p=fa[p]; if (!p) fa[np]=1; else { int q=c[p][x]; if (mx[q]==mx[p]+1) fa[np]=q; else { int nq=++cnt; mx[nq]=mx[p]+1; memcpy(c[nq],c[q],sizeof(c[q])); fa[nq]=fa[q];fa[q]=fa[np]=nq; while (p&&c[p][x]==q) c[p][x]=nq,p=fa[p]; } } } int main() { scanf("%s",a+1);scanf("%s",b+1); n=strlen(a+1);m=strlen(b+1); last=1;F(i,1,n) add(a[i]-'a'),sz[last][0]++; last=1;F(i,1,m) add(b[i]-'a'),sz[last][1]++; calc(); cout<<ans<<endl; return 0; }


生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生