4566: [Haoi2016]找相同字符
对第一个串建出后缀自动机,统计出每个节点对答案的贡献,再用第二个串跑一遍统计答案。
//# pragma GCC optimize ("O2")
//# pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
#define lb(x) ((x)&(-x))
#define out(i,a,now) for(int i=a.be[now],to=a.v[i];~i;i=a.ne[i],to=a.v[i])
#define fo(i,a,b) for(i=(a);i<=(b);++i)
#define fd(i,a,b) for(i=(a);i>=(b);--i)
#define mid ((l+r)>>1)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
#define mp(a,b) make_pair(a,b)
#define qk(x) memset(x,0,sizeof(x))
#define RG register
#define SF scanf
#define PF printf
#define FP freopen
#define gs(x) (tr[tr[x].f][1]==x)
#define cpy(a,b) memcpy(a,b,sizeof(a))
#ifdef Mogician
#endif
using namespace std;
typedef long long LL;
typedef double DB;
typedef pair<LL,LL> Pair;
template <class T> void cmax(T &a,T b)
{
a=max(a,b);
}
template <class T> void cmin(T &a,T b)
{
a=min(a,b);
}
const LL maxn=201000,alpha=26;
struct data
{
LL nxt[alpha+2],ma,f,sum,cnt;
data()
{
ma=f=sum=cnt=0;
qk(nxt);
}
LL& operator [](const LL& b)
{
return nxt[b];
}
}tr[maxn*2];
struct Suffix_Automaton
{
LL cnt,root,last;
LL new_node(LL ma)
{
tr[++cnt]=data();
tr[cnt].ma=ma;
return cnt;
}
Suffix_Automaton()
{
cnt=0;
root=last=new_node(0);
}
void add(LL x)
{
LL p=last,np=new_node(tr[p].ma+1);
last=np; tr[np].cnt=1;
for(;p&&!tr[p][x];p=tr[p].f) tr[p][x]=np;
if (!p) tr[np].f=root;
else
{
LL q=tr[p][x];
if (tr[q].ma==tr[p].ma+1) tr[np].f=q;
else
{
LL nq=new_node(tr[p].ma+1);
cpy(tr[nq].nxt,tr[q].nxt);
tr[nq].f=tr[q].f; tr[q].f=nq; tr[np].f=nq;
for(;p&&tr[p][x]==q;p=tr[p].f) tr[p][x]=nq;
}
}
}
}sam;
LL n,a[maxn*2],flag;
char s[maxn];
bool cmp(const LL& a,const LL& b)
{
return tr[a].ma*flag>tr[b].ma*flag;
}
int main()
{
#ifdef Mogician
FP("bzoj4566.in","r",stdin);
FP("bzoj4566.out","w",stdout);
#endif
SF("%s",s);
n=strlen(s);
LL i;
fo(i,0,n-1) sam.add(s[i]-'a');
fo(i,1,sam.cnt) a[i]=i;
flag=1;
sort(a+1,a+sam.cnt+1,cmp);
fo(i,1,sam.cnt) tr[tr[a[i]].f].cnt+=tr[a[i]].cnt;
flag=-1;
sort(a+1,a+sam.cnt+1,cmp);
LL ans=0;
fo(i,2,sam.cnt)
{
tr[a[i]].sum+=tr[tr[a[i]].f].sum+(tr[a[i]].ma-tr[tr[a[i]].f].ma)*tr[a[i]].cnt;
}
SF("%s",s);
n=strlen(s);
LL now=sam.root,len=0;
//维护最长匹配长度len的方法:
fo(i,0,n-1)
{
if (!tr[now][s[i]-'a'])
{
while (now&&!tr[now][s[i]-'a']) now=tr[now].f;
if (!now) now=sam.root,len=0;
else
{
len=tr[now].ma+1;
now=tr[now][s[i]-'a'];
}
}
else
{
now=tr[now][s[i]-'a'];
++len;
}
assert(tr[tr[now].f].ma<len);
ans+=tr[now].sum-(tr[now].ma-len)*tr[now].cnt;//减去不足ma的部分
}
PF("%lld",ans);
}