题目传送门
分析:
(有生之年考场上会做的后缀数组题
(后缀数组是个好东西,我有头发的时候天天写
把两个串接在一起,中间隔一个分隔符
把\(sa\)和\(height\)跑出来
把我们所需要配对的子串首位置的\(rk\)位置标记
两个子串\(s1,s2\)匹配代价为\(K-lcp(s1,s2)\)
转化为区间\(height\)最小值
于是变成了这样一个问题。。
数轴上有红蓝两种点,两两匹配价值为两点之间单位线段权值的最小值
要求价值最大
做法很经典了,把线段从大到小排序,并查集合并计算就好了。。
wdnmd,\(height\)最小值没和\(K\)取min,竟然能混70分???
(出题人用脚造数据(划去)
哦好像后缀自动机也能做
反向广义后缀自动机建出来,两个子串配对价值为LCA的len
\(O(n)\)胡乱DP一顿(口胡)
代码是后缀数组
#include
#include
#include
#include
#include
#include
#include
#define maxn 300005
#define MOD 1000000007
#define INF 0x3f3f3f3f
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int N,n,m,K;
int sa[maxn],rk[maxn],tp[maxn],tax[maxn],hght[maxn];
char s[maxn];
int mn[maxn][19],lg[maxn];
int f[maxn],sz1[maxn],sz2[maxn],id[maxn];
long long ans;
inline bool cmp(int x,int y){return hght[x]>hght[y];}
inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline void Rsort()
{
for(int i=0;i<=m;i++)tax[i]=0;
for(int i=1;i<=n;i++)tax[rk[tp[i]]]++;
for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
}
inline bool check(int x,int y,int k)
{return tp[x]==tp[y]&&tp[x+k]==tp[y+k];}
inline void getsa()
{
for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;
m=127,Rsort();
for(int p=1,w=1;pw)tp[++p]=sa[i]-w;
Rsort(),swap(rk,tp),rk[sa[1]]=p=1;
for(int i=2;i<=n;i++)rk[sa[i]]=check(sa[i],sa[i-1],w)?p:++p;
}
int k=0;
for(int i=1;i<=n;i++)
{
k=k?k-1:k;
for(int j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
hght[rk[i]]=k;
}
}
inline int query(int l,int r)
{
int k=lg[r-l+1];
return min(mn[l][k],mn[r-(1<y)swap(x,y);
if(x==y)return n-sa[x]+1;
return query(x+1,y);
}
int main()
{
for(int i=0;i<19;i++)lg[1<