链接
http://poj.org/problem?id=3415
题解
也不知是我码力下降了还是怎么的,这题竟然用了2.5h才搞定
先求一下后缀数组以及
height
h
e
i
g
h
t
那么最暴力的方法就先按照
K
K
分组,每一个组内对每个属于串的后缀,向上方查找所以属于
A
A
的后缀,一路统计
这样
O(n2)
O
(
n
2
)
是不行的
对于每一个属于
B
B
的后缀,我们面临的问题都是相似的,考虑能否进行优化
显然两个属于的后缀中间的一些
height
h
e
i
g
h
t
会影响到上面某些属于
A
A
的后缀的贡献,如果我们把每个属于的后缀的贡献记录下来,每次加入一个后缀的时候,看下影响到了那些后缀的贡献,取个
min
m
i
n
就好了
这样就想到了单调数据结构,如果我按照单调增的顺序存储这些贡献值,那么每次只需要修改结尾的连续几个
但是这样依然是不行的,修改的次数可能会很多,观察到修改之后这些贡献值都是相等的,那么我们就把修改后的元素合并一下,记录(出现次数,贡献值)这样的二元组,搞一搞就
OK
O
K
了
这个东西好像就是单调栈?
从
height
h
e
i
g
h
t
的值域的角度考虑,这个算法确实是
O(n)
O
(
n
)
的
但是我只会
O(nlogn)
O
(
n
l
o
g
n
)
的后缀数组,所以最后复杂度是
O(nlogn)
O
(
n
l
o
g
n
)
代码
//后缀数组
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
#define maxn 200010
#define cl(x) memset(x,0,sizeof(x))
#define inf (1ll<<60)
#define ll long long
using namespace std;
struct con{ll cnt, contribution;}stack[maxn];
ll N, sa[maxn], rank[maxn], height[maxn], wa[maxn], wb[maxn], ws[maxn], wv[maxn], r[maxn], K, top, belong[maxn];
char A[maxn], B[maxn];
bool cmp(ll *r, ll a, ll b, ll l){return r[a]==r[b] and r[a+l]==r[b+l];}
void build_sa(ll *r, ll n, ll m)
{
n++;
ll i, j, k=0, p, *x=wa, *y=wb, *t;
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[x[i]=r[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
for(p=j=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++)ws[i]=0;
for(i=0;i<n;i++)ws[wv[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
for(i=0;i<n;i++)rank[sa[i]]=i;
for(i=0;i<n-1;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}
void init()
{
ll i, j, la, lb;
cl(r), cl(sa), cl(rank), cl(height), cl(wa), cl(wb);
scanf("%s%s",A,B);
la=strlen(A), lb=strlen(B);
for(i=0;i<la;i++)r[i]=A[i], belong[i]=1;
for(i=0;i<lb;i++)r[la+1+i]=B[i], belong[la+1+i]=2;
r[la]='|';
N=la+1+lb;
build_sa(r,N,300);
}
void calc()
{
ll ans=0, i, j, pre=0, cnt, now;
for(i=0;i<=N;i++)
if(height[i+1]<K)
{
top=0, now=0;
for(j=pre;j<=i;j++)
{
cnt=0;
while(top and height[j]-K+1<stack[top].contribution)now-=stack[top].cnt*stack[top].contribution, cnt+=stack[top].cnt, top--;
if(cnt)stack[++top]=(con){cnt,height[j]-K+1}, now+=cnt*(height[j]-K+1);
if(belong[sa[j]]==1)stack[++top]=(con){1,inf}, now+=inf;
else ans+=now;
}
pre=i+1;
}
pre=0;
for(i=0;i<=N;i++)
if(height[i+1]<K)
{
top=0, now=0;
for(j=pre;j<=i;j++)
{
cnt=0;
while(top and height[j]-K+1<stack[top].contribution)now-=stack[top].cnt*stack[top].contribution, cnt+=stack[top].cnt, top--;
if(cnt)stack[++top]=(con){cnt,height[j]-K+1}, now+=cnt*(height[j]-K+1);
if(belong[sa[j]]==2)stack[++top]=(con){1,inf}, now+=inf;
else ans+=now;
}
pre=i+1;
}
printf("%lld\n",ans);
}
int main()
{
while(scanf("%lld",&K),K)init(), calc();
return 0;
}