ICPC2021台北 CF103443K Insertion Array 题解
题目描述
\(T\) 组数据,给定字符串 \(a,b\) ,记 \(|a|=n,|b|=m\) 。
对 \(\forall 0\le x\le m\) ,记第 \(x\) 个字符串为 \(b[1\sim x]+a+b[x+1\sim m]\) 。
记将这 \(m\) 个字符串按照字典序排序后,排名为 \(i\) 的是第 \(c_i\) 个字符串。
求 \(\big(\sum_{i=0}^mc_i\cdot 1234567^i\big)\bmod(10^9+7)\) 的值。
数据范围
- \(1\le T\le 4\cdot 10^4,1\le\sum n,\sum m\le 2\cdot 10^6\) 。
时间限制 \(\texttt{3s}\) ,空间限制 \(\texttt{1GB}\) 。
分析
冷知识: \(4\cdot 10^6\) 的后缀数组要跑 \(\texttt{2s}\) 。
我们只需要做到快速比较两个字符串字典序,外面套个 sort 的壳子即可。
假设正在比较第 \(x,y\) 个字符串,不妨 \(x\le y\) 。
画一下图就知道我们需要对 \(y-x\) 和 \(n\) 的大小关系分类讨论。
如果 \(y-x\le n\) (相交),需要依次进行三轮比较:
- \(a[1\sim y-x]\) 与 \(b[x+1\sim y]\) 。
- \(a[y-x+1\sim n]\) 与 \(a[1\sim n-(y-x)]\) 。
- \(b[x+1\sim y]\) 与 \(a[n-(y-x)+1\sim n]\) 。
如果 \(y-x\gt n\) (相离),也需要进行三轮比较:
- \(a[1\sim n]\) 与 \(b[x+1\sim x+n]\) 。
- \(b[x+1\sim y-n]\) 与 \(b[x+n+1\sim y]\) 。
- \(b[y-n+1\sim y]\) 与 \(a[1\sim n]\) 。
容易想到哈希 + 二分或者后缀数组求 \(\texttt{lcp}\) ,然而都过不去。
我们希望第一轮比较能得出前 \(y-x\) 个字符的 \(\texttt{lcp}\) 。
对于相离的情况,如果前 \(n\) 个字符相同(也就是会进入第二轮比较),根据传递性,接下来等效于用 \(b[x+n+1]\) 开始的前 \(n\) 个字符和 \(a\) 继续比较,以此类推。
将 \(a\) 复制若干次直到长度 \(\ge m\) ,再拼上一个字符串 \(b\) ,跑 \(\text{EXKMP}\) ,这样 \(b[x+1]\) 开头的后缀与整串的 \(\texttt{lcp}\) 即为所求。
我们希望第二轮比较能得出后 \(x\) 个字符的 \(\texttt{lcp}\) 。
由于第一轮比较没有出结果,所以第 \(x\) 个字符串相当于将若干个 \(a\) 拼起来再删掉前 \(y-x\) 个字符,而第 \(y\) 个字符串刚好就是 \(a\) ,因此答案为第 \(y-x+1\) 个字符开头的后缀与整串的 \(\texttt{lcp}\) 。
时间复杂度 \(\mathcal O(n+m\log m)\) 。
#include<bits/stdc++.h>
using namespace std;
const int maxn=8e6+5,mod=1e9+7;
int k,m,n,t,now,res;
int c[maxn],nxt[maxn];
char a[maxn],b[maxn],s[maxn];
bool cmp(int x,int y)
{
int l=0,op=0;
if(x>y) swap(x,y),op=1;
if((l=nxt[now+x+1])<y-x) return (s[l+1]<s[now+x+l+1])^op;
if((l=nxt[y-x+1])<n) return (s[y-x+l+1]<s[l+1])^op;
return op;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%s%s",a+1,b+1),n=strlen(a+1),m=strlen(b+1),k=res=0;
while(k<=n+m) for(int i=1;i<=n;i++) s[++k]=a[i];
now=k;
for(int i=1;i<=m;i++) s[++k]=b[i];
s[k+1]='#';
for(int i=1;i<=k;i++) nxt[i]=0;
for(int i=2,pos=0,mxr=0;i<=k;i++)
{
if(i<=mxr) nxt[i]=min(nxt[i-pos+1],mxr-i+1);
while(s[i+nxt[i]]==s[nxt[i]+1]) nxt[i]++;
if(i+nxt[i]-1>mxr) pos=i,mxr=i+nxt[i]-1;
}
for(int i=0;i<=m;i++) c[i]=i;
res=0,sort(c,c+m+1,cmp);
for(int i=m;i>=0;i--) res=(1234567ll*res+c[i])%mod;
printf("%d\n",res);
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/17366781.html
浙公网安备 33010602011771号