wrkwrkwrk
2024-11-17 17:47:00
先考虑如何对一个三元组
从左向右考虑,每次从目前已经包括的区域贪心地选取尽可能后的串。之后和
显然可以固定左端点,贪心对每个
发现对贪心取得的序列贪心拓展是简单的。考虑每次把扩展的答案进行计数。
一段区间
考虑我们如何计算这个二阶差分:对
先处理第一项:其为
考虑每次贪心扩展的过程:找到最大的扩展区域,并在新扩展区域找到下一步可能最大的扩展区域。
“找到最大”可以 ST 表。以上过程可以倍增:跳
第二项类似。现在考虑第三项:再次考虑跳的过程:其相当于有一些起点,每次往一个位置赋值并且跳,每个点都跳
可能在某一步骤开始不动。考虑跳
#include<bits/stdc++.h>
using namespace std;
bool st;
namespace _wrk{;
#define int long long
string s[500005],t;
int sl[500005];
unsigned long long bas[500005],tb[500005];
const int base=41;
vector<int>nex[500005];
int maxr[500005];
int st[20][500005];
int stp[20][500005];
int gemax(int l,int r){
int le=r-l+1,p=__lg(le);
return max(st[p][l],st[p][r-(1ll<<p)+1]);
}
int gemaxpos(int l,int r){
int le=r-l+1,p=__lg(le);
if(gemax(l,r)==st[p][r-(1ll<<p)+1])return stp[p][r-(1ll<<p)+1];
else return stp[p][l];
}
int pans,ans[500005],dans[500005],ddans[500005];
int nec[500005][21],suc[500005][21];
int pk[500005];
//int nec[500005][20];
signed main(){
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
bas[0]=1;
for(int i=1;i<=500001;i++)bas[i]=bas[i-1]*base;
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int id,n,k;
cin>>id>>n>>k;
for(int i=1;i<=n;i++){
cin>>s[i];
sl[i]=s[i].length();
s[i]='&'+s[i]+'&';
}
cin>>t;
int m=t.length();
t='$'+t+'$';
for(int i=1;i<=m;i++){
maxr[i]=i;
tb[i]=tb[i-1]*base+t[i]-'a'+1;
}
for(int i=1;i<=n;i++){
nex[i].resize(s[i].size());
nex[i][0]=0;
for(int j=1;j<=sl[i];j++){
nex[i][j]=nex[i][j-1]*base+s[i][j]-'a'+1;
}
for(int j=1;j<=m;j++){
int l=0,r=sl[i]+1;
while(l+1<r){
int mid=(l+r)>>1;
if(j+mid-1<=m&&nex[i][mid]==tb[j+mid-1]-tb[j-1]*bas[mid])l=mid;
else r=mid;
}
maxr[j]=max(maxr[j],j+l);
// cout<<l<<' '<<r<<endl;
}
}
maxr[m+1]=m+1;
for(int i=1;i<=m+1;i++){
st[0][i]=maxr[i];
stp[0][i]=i;
}
for(int j=1;j<=20;j++){
for(int i=1;i+(1ll<<j)-1<=m+1;i++){
st[j][i]=max(st[j-1][i],st[j-1][i+(1ll<<(j-1))]);
if(st[j-1][i]>st[j-1][i+(1ll<<(j-1))])stp[j][i]=stp[j-1][i];
else stp[j][i]=stp[j-1][i+(1ll<<(j-1))];
}
}
nec[m+1][0]=m+1;
suc[m+1][0]=m+1;
for(int i=1;i<=m;i++){
nec[i][0]=gemaxpos(i,maxr[i]);
suc[i][0]=maxr[i];
}
for(int j=1;j<=20;j++){
for(int i=1;i<=m+1;i++){
nec[i][j]=nec[nec[i][j-1]][j-1];
suc[i][j]=suc[i][j-1]+suc[nec[i][j-1]][j-1];
// cout<<i<<' '<<j<<' '<<nec[i][j]<<' '<<suc[i][j]<<endl;
}
}
for(int l=1;l<=m;l++){
int r=l;
int su=0;int kk=k;
// cout<<l<<' '<<kk<<endl;
for(int j=20;j>=0;j--){
while(kk>=1ll<<j){
// cout<<r<<' '<<j<<' '<<' '<<suc[r][j]<<endl;
su+=suc[r][j];
r=nec[r][j];
kk-=1ll<<j;
}
}
// cout<<r<<endl;
pans+=su-l*k;
ddans[l]+=su-l*k;
ddans[l+1]-=su-l*k+k;
pk[l]++;
int p=r;r=l;
int ste=0;
for(int i=20;i>=0;i--){
while((ste+(1ll<<i))<=k&&nec[r][i]!=p){
ste+=1ll<<i;
r=nec[r][i];
}
}
if(r!=p)ste++;
pk[p]--;
// cout<<l<<' '<<r<<' '<<p<<endl;
ddans[maxr[p]+1]+=k-ste;
}
// for(int i=1;i<=m;i++){
// cout<<pk[i]<<' ';
// }
for(int i=1;i<=m;i++){
ddans[maxr[i]+1]+=pk[i];
pk[nec[i][0]]+=pk[i];
}
cout<<pans<<'\n';
for(int i=1;i<=m;i++){
// cout<<ddans[i]<<' ';
dans[i]=dans[i-1]+ddans[i];
ans[i]=ans[i-1]+dans[i];
cout<<ans[i]<<' ';
}
return 0;
}
}
bool en;
signed main(){
#ifdef LOCAL_WRK
cerr<<"[Static Memory : "<<fixed<<((&st)-(&en))/1048576.0<<"MB]"<<endl;
#endif
return _wrk::main();
}
AC 记录。