1. 程式人生 > >【刷題】BZOJ 4566 [Haoi2016]找相同字符

【刷題】BZOJ 4566 [Haoi2016]找相同字符

多少 sca www 大會 noi2015 unsigned put div 就是

Description

給定兩個字符串,求出在兩個字符串中各取出一個子串使得這兩個子串相同的方案數。兩個方案不同當且僅當這兩個子串中有一個位置不同。

Input

兩行,兩個字符串s1,s2,長度分別為n1,n2。1 <=n1, n2<= 200000,字符串中只有小寫字母

Output

輸出一個整數表示答案

Sample Input

aabb
bbaa

Sample Output

10

Solution

又是那個單調棧的套路。。。
首先把兩個串接在一起,利用單調棧求出這個串中有多少方案 \(a\) 使得自己的某個子串可以匹配另一個子串
然後分別對給的兩個小串求一個這個 ,得到 \(b\)\(c\)


那麽 \(a-b-c\) ,就是答案了
其實就是個簡單容斥, \(a\) 代表兩個串互相匹配的方案數加上兩個串自己匹配自己的方案數,減去了 \(b\)\(c\) 後就是兩個串互相匹配的方案數了
不知道單調棧套路的可以見【刷題】BZOJ 3238 [Ahoi2013]差異和【刷題】BZOJ 4199 [Noi2015]品酒大會

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=400000+10; int n,m,n1,n2,SA[MAXN],cnt[MAXN],rk[MAXN],nxt[MAXN],lp[MAXN],rp[MAXN],height[MAXN]; char s1[MAXN],s2[MAXN],s[MAXN]; ll ans; template<typename T> inline void read(T &x) { T data=0,w=1; char ch=0; while(ch!='-'&&(ch<'0'||ch>'9'
))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar(); x=data*w; } template<typename T> inline void write(T x,char ch='\0') { if(x<0)putchar('-'),x=-x; if(x>9)write(x/10); putchar(x%10+'0'); if(ch!='\0')putchar(ch); } template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} template<typename T> inline T min(T x,T y){return x<y?x:y;} template<typename T> inline T max(T x,T y){return x>y?x:y;} inline void GetSA() { m=300; memset(nxt,0,sizeof(nxt)); for(register int i=1;i<=m;++i)cnt[i]=0; for(register int i=1;i<=n;++i)rk[i]=s[i]; for(register int i=1;i<=n;++i)cnt[rk[i]]++; for(register int i=1;i<=m;++i)cnt[i]+=cnt[i-1]; for(register int i=n;i>=1;--i)SA[cnt[rk[i]]--]=i; for(register int k=1,ps;k<=n;k<<=1) { ps=0; for(register int i=n-k+1;i<=n;++i)nxt[++ps]=i; for(register int i=1;i<=n;++i) if(SA[i]>k)nxt[++ps]=SA[i]-k; for(register int i=1;i<=m;++i)cnt[i]=0; for(register int i=1;i<=n;++i)cnt[rk[i]]++; for(register int i=1;i<=m;++i)cnt[i]+=cnt[i-1]; for(register int i=n;i>=1;--i)SA[cnt[rk[nxt[i]]]--]=nxt[i]; std::swap(rk,nxt); rk[SA[1]]=1,ps=1; for(register int i=2;i<=n;rk[SA[i]]=ps,++i) if(nxt[SA[i]]!=nxt[SA[i-1]]||nxt[SA[i]+k]!=nxt[SA[i-1]+k])ps++; if(ps>=n)break; m=ps; } for(register int i=1,j,k=0;i<=n;height[rk[i++]]=k) for(k=k?k-1:k,j=SA[rk[i]-1];s[i+k]==s[j+k];++k); } inline void calc(int tp) { memset(lp,0,sizeof(lp)); memset(rp,0,sizeof(rp)); for(register int i=2,j;i<=n;lp[i]=j,++i) for(j=i-1;j>=2&&height[j]>=height[i];j=lp[j]); for(register int i=n,j;i>=2;rp[i]=j,--i) for(j=i+1;j<=n&&height[j]>height[i];j=rp[j]); for(register int i=2;i<=n;++i) { lp[i]++,rp[i]--; ans+=1ll*tp*height[i]*(i-lp[i]+1)*(rp[i]-i+1); } } int main() { scanf("%s",s1+1);scanf("%s",s2+1); n1=strlen(s1+1);n2=strlen(s2+1); memcpy(s,s1,sizeof(s));n=n1;GetSA();calc(-1); memcpy(s,s2,sizeof(s));n=n2;GetSA();calc(-1); n=n1+n2+1; for(register int i=1;i<=n1;++i)s[i]=s1[i]; s[n1+1]='z'+1; for(register int i=1;i<=n2;++i)s[n1+i+1]=s2[i]; GetSA();calc(1); write(ans,'\n'); return 0; }

【刷題】BZOJ 4566 [Haoi2016]找相同字符