Description
Solution
几乎没有什么思维难度
先将原树建成一个Trie,此时Trie上的节点已经合并了一些终点了,合并的时候DP背包一下
然后再BFS把Trie建成SAM,那么就变成了在Fail树上DP,子树选取,直接背包即可
代码略为猥琐
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#define mo 998244353
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 300005
#define LL long long
using namespace std;
int t[N][6],t1[N][6],n,m1,m,num,n1,n2,fail[N],mx[N],vl[N],d[N],nt[2*N],dt[2*N],fs[N],dv[N],pt[N],dc[N];
LL f[N][17],pr[N],g[N][17],s[N][17];
bool bz[N];
void link(int x,int y)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
}
void dfs(int k,int ft,int q)
{
int c=vl[k];
if(!t1[q][c]) t1[q][c]=++n1;
q=t1[q][c];
f[q][0]=1;
fod(j,16,1) f[q][j]=(f[q][j]+f[q][j-1]*pr[k])%mo;
for(int i=fs[k];i;i=nt[i]) if(dt[i]!=ft) dfs(dt[i],k,q);
}
void bfs()
{
int l=0,r=0;
n2=1;
fo(i,0,num-1)
{
if(!bz[t1[1][i]]&&t1[1][i])
{
bz[t1[1][i]]=1;
d[++r]=t1[1][i];
dc[r]=i;
dv[t1[1][i]]=1;
}
}
while(l<r)
{
int k=d[++l],p=dv[k],c=dc[l],ls=++n2;
mx[ls]=mx[p]+1,pt[ls]=k;
fo(i,0,16) g[ls][i]=f[k][i];
while(p&&!t[p][c]) t[p][c]=ls,p=fail[p];
if(p)
{
int q=t[p][c];
if(mx[q]==mx[p]+1) fail[ls]=q;
else
{
fail[++n2]=fail[q];
fail[q]=fail[ls]=n2;
mx[n2]=mx[p]+1;
fo(i,0,num-1) t[n2][i]=t[q][i];
while(p&&t[p][c]==q) t[p][c]=n2,p=fail[p];
}
}
else fail[ls]=1;
fo(i,0,num-1)
{
if(!bz[t1[k][i]]&&t1[k][i])
{
bz[t1[k][i]]=1;
d[++r]=t1[k][i];
dc[r]=i;
dv[t1[k][i]]=ls;
}
}
}
}
void dp(int k)
{
g[k][0]=1;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
dp(p);
if(k>1)
fod(j,16,1)
fo(q,1,j) g[k][j]=(g[k][j]+g[p][q]*g[k][j-q])%mo;
}
if(k>1) fo(j,1,16) s[mx[fail[k]]+1][j]+=g[k][j],s[mx[k]+1][j]-=g[k][j];
}
int main()
{
cin>>n>>m>>num;
scanf("\n");
fo(i,1,n)
{
char ch=getchar();
vl[i]=ch-'a';
}
fo(i,1,n) scanf("%lld",&pr[i]);
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);
link(x,y),link(y,x);
}
n1=n2=1;
dfs(1,0,1);
bfs();
memset(fs,0,sizeof(fs));
memset(nt,0,sizeof(nt));
m1=0;
fo(i,2,n2) link(fail[i],i);
dp(1);
fo(i,1,2*n)
fo(j,1,16) s[i][j]=(s[i][j]+s[i-1][j])%mo;
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",(s[x][y]+mo)%mo);
}
}