Hoks
2024-11-18 15:58:37
感觉很神的题。
个人感觉比简单的字符串问题要 hard 很多。
优先考虑下第一问先。
我们显然的有一个暴力的做法,直接进行一个区间 dp。
转移就是设两个好的三元组
这个复杂度是
然后我们来考虑优化。
类似于简单的字符串问题中的
那么就是
原因很简单,你直接多插入一个空的字符串在末尾就行了。
我们现在的问题就变成了计算对于每个
那么我们就可以想到枚举
把一个串拆分为最小段数的前缀,其中前缀让我们想到了 trie。
所以我们只要把
具体的,我们尝试把这段字符串
那这样的话我们先枚举长度
复杂度
上面的代码理论而言不能拿到
其实这里就是一个平衡复杂度的过程。
每次都在 trie 上跳一遍太浪费时间了,我们不妨直接预处理出来每个点开始能最多跳几步,这样就是一个
然后查询就变成了一个树链的
复杂度
然后这个做法貌似就没什么优化的余地了没前途的做法,我们考虑进一步观察性质。
其实我们可以发现这里还有一个单调性。
就是如果
略证一下,既然
拆分出的两者中前者都不能用
有了这个单调性我们就有了另一种 dp 的定义方式。
这次我们不钦定
由前面的性质,我们知道可能的
设这个定义的最右端点为
这东西就是
然后我们考虑暴力的转移,对于
考虑下这个式子的意义。
就是对于
这个东西有关的值只有
那么总的复杂度就是
当然如果你用四毛子就可以把丑陋的
然后继续优化这个东西。
发现复杂度瓶颈在 trie 的这个预处理上,我们考虑加速这个预处理。
这个预处理其实就是在找从位置
这种匹配我们可以用 hash+二分的经典技巧来加速,可以做到
这样的总复杂度就来到了
当然你也可以用 Z 函数直接剥掉 hash+二分的
code by Hoks。
当然你还可以通过数据点分治的方法拿到
然后我们来考虑最后一个优化。
前面不管我们怎么优化,都会有一个无法逾越的瓶颈:
其实我们可以注意到的是,对于这
因为所有的
考虑观察这些取值之间互相转移的性质。
不妨设
因为
所以
那么我们考虑
换元法,我们令
然后我们就得到了
这东西长得一脸图的样子,我们直接建图,给
那么我们就可以把第一问的答案用一个形式化的式子表达出来:
把中间平凡的
后两项是平凡的,只需要考虑第一项就可以了。
因为
那么就是对于每个
但是注意树的根节点有自环,要特殊处理。
使用 Z 函数,这样我们就在
当然如果会四毛子+长剖可以去掉
当然这个东西他求的
code by Hoks。
实际得分
做完第一问后,我们来考虑第二问。
首先是对于最开头写的
在算出
复杂度还是
接着是
因为其本质并没有区别,所以第二问的做法相同。
我们现在已经处理出了
也就是对于
第一个期望得分
实际而言得分都是
代码可以看上面附的链接。
然后是对于有前途钦定了
第一种是无脑的做法,我们直接通过
这样期望得分
code by Hoks。
但这样还是没有前途太劣了。
我们不妨直接对每个
他的贡献就是对于区间
这里面有一个
然后再差分一次前缀和累加就行了。
具体的先给
然后前缀和累加一次。
再给
复杂度和前面的期望
code by Hoks,非常丑陋就是给一个东西拼了两次()。
然后我们考虑
根据前面的
我们尝试把刚刚的
修改之后我们的具体操作就是:
这其实就只是把刚刚的操作扔到森林上来了。
细节注意点还是相同的,注意根节点的自环。
实现上而言,我们可以不用真的这样二阶前缀和,直接二阶差分把值差分出来就行了。
复杂度仍是
#include<bits/stdc++.h>
#define ls (p<<1)
#define rs (ls|1)
#define mid ((l+r)>>1)
#define int long long
using namespace std;
const int N=1e6+10,V=315,M=23,INF=1e9,mod=998244353;
int n,m,k,ans,l[N],z[N<<1],g[N];char s[M][N],t[N],ss[N<<1];
vector<int>e[N];int top,st[N],f[N],kf[N],mp[N],a[N],b[N],c[N],d[N];
int tt[M][N],stt[M][N];
namespace Fast_IO
{
static char buf[1000000],*paa=buf,*pd=buf,out[10000000];int length=0;
#define getchar() paa==pd&&(pd=(paa=buf)+fread(buf,1,1000000,stdin),paa==pd)?EOF:*paa++
inline int read()
{
int x(0),t(1);char fc(getchar());
while(!isdigit(fc)){if(fc=='-') t=-1;fc=getchar();}
while(isdigit(fc)) x=(x<<1)+(x<<3)+(fc^48),fc=getchar();
return x*t;
}
inline void flush(){fwrite(out,1,length,stdout);length=0;}
inline void put(char c){if(length==9999999) flush();out[length++]=c;}
inline void put(string s){for(char c:s) put(c);}
inline void print(int x)
{
if(x<0) put('-'),x=-x;
if(x>9) print(x/10);
put(x%10+'0');
}
inline bool chk(char c) { return !(c>='a'&&c<='z'||c>='A'&&c<='Z'||c>='0'&&c<='9'||c=='|'||c=='-'); }
inline bool ck(char c) { return c!='\n'&&c!='\r'&&c!=-1&&c!=' '; }
inline void rd(char s[],int&n)
{
s[++n]=getchar();
while(chk(s[n])) s[n]=getchar();
while(ck(s[n])) s[++n]=getchar();
n--;
}
}
using namespace Fast_IO;
namespace function_Z
{
inline void get_Z(char s[],int n,int z[])
{
for(int i=2,l=1,r=0;i<=n;i++)
{
z[i]=i>r?0:min(z[i-l+1],r-i+1);
while(i+z[i]<=n&&s[z[i]+1]==s[i+z[i]]) z[i]++;
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}z[1]=n;
}
}
using namespace function_Z;
inline void dfs1(int u,int rt)
{
st[++top]=u;d[u]=d[f[u]]+1;b[u]=b[f[u]]+g[u];
if(top>=k) kf[u]=st[top-k+1];
else{kf[u]=rt;if(mp[u]) ans+=(k-top)*g[rt];}
for(int v:e[u]) dfs1(v,rt);a[f[kf[u]]]--,a[u]++;top--;
}
inline void dfs2(int u,int t)
{
for(int v:e[u]) dfs2(v,t),a[u]+=a[v];ans+=a[u]*g[u];int cur=0;
if(d[u]>=k) cur=b[u]-b[f[kf[u]]]-k*(u-1);
else cur=(k-d[u])*g[t]+b[u]-k*(u-1),c[g[t]+2]+=k-d[u];
c[u]+=cur,c[u+1]-=cur+k,c[g[u]+2]+=a[u];
}
inline void solve()
{
n=read();k=read();for(int i=1;i<=n;i++) rd(s[i],l[i]);rd(t,m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) if(s[i][1]==t[j]) mp[j]=1;
for(int j=1;j<=l[i];j++) ss[j]=s[i][j];
for(int j=1;j<=m;j++) ss[j+l[i]]=t[j];get_Z(ss,m+l[i],z);
for(int j=1;j<=m;j++) g[j]=max(g[j],j+min(l[i],z[j+l[i]])-1);
}for(int j=1;j<=m;j++) if(mp[j]) stt[0][j]=g[j],tt[0][j]=j;
for(int j=1;j<M;j++)
for(int i=1;i+(1<<j)-1<=m;i++)
{
if(stt[j-1][i]>stt[j-1][i+(1<<j-1)]) tt[j][i]=tt[j-1][i];
else tt[j][i]=tt[j-1][i+(1<<j-1)];
stt[j][i]=max(stt[j-1][i],stt[j-1][i+(1<<j-1)]);
}
for(int i=1;i<=m;i++)
{
if(!mp[i]){f[i]=i;continue;}int r=g[i]+1,K=log2(r-i+1);
if(stt[K][i]>stt[K][r-(1<<K)+1]) f[i]=tt[K][i];
else f[i]=tt[K][r-(1<<K)+1];
if(f[i]!=i) e[f[i]].emplace_back(i);else f[i]=0;
}for(int i=1;i<=m;i++) if(!f[i]) dfs1(i,i),dfs2(i,i);
for(int i=1;i<=m;i++) if(mp[i]) ans-=(i-1)*k;
print(ans);put('\n');
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=1;i<=m;i++) print(c[i]),put(' ');
}
signed main()
{
int T=1,tp=read();
// T=read();
while(T--) solve();
genshin:;flush();return 0;
}