CF2183F - Jumping Man
首先把相同字符串数量平方转化成选两个相同字符串的方案数。
记 \(f _ {u, v}\) 表示取两个相等的字符串,第一个字符的位置分别为 \(u, v\) 的方案数。转移和求答案都是在 dfn 序上的矩形求和,二维前缀和就可以维护。
#include<cstdio>
#define N 5005
using namespace std;
const int mod=998244353;
int T,n,f[N][N],sf[N][N];
int tot,head[N],nxt[N*2],ver[N*2];
int num,dfn[N],dln[N],ord[N];
char s[N];
void insert(int x,int y) {
ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
void dfs(int x,int fa) {
dfn[x]=++num,ord[num]=x;
for(int i=head[x],y;i;i=nxt[i])
if((y=ver[i])!=fa) dfs(y,x);
dln[x]=num;
}
int ask(int l1,int r1,int l2,int r2) {
return ((0ll+sf[l1][l2]-sf[r1+1][l2]-sf[l1][r2+1]+sf[r1+1][r2+1])%mod+mod)%mod;
}
int main() {
scanf("%d",&T);
XJX:while(T--) {
tot=num=0;
for(int i=1;i<=n;i++) {
head[i]=0;
for(int j=1;j<=n;j++) f[i][j]=sf[i][j]=0;
}
scanf("%d%s",&n,s+1);
for(int i=1,x,y;i<n;i++)
scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
dfs(1,0);
for(int i=n;i;i--) {
for(int j=n;j;j--) {
if(s[ord[i]]==s[ord[j]]) {
f[i][j]=(1ll+ask(i+1,dln[ord[i]],j+1,dln[ord[j]]))%mod;
}
}
for(int j=n;j;j--) sf[i][j]=(sf[i][j+1]+f[i][j])%mod;
for(int j=n;j;j--) sf[i][j]=(sf[i][j]+sf[i+1][j])%mod;
}
for(int i=1;i<=n;i++) printf("%d ",ask(dfn[i],dln[i],dfn[i],dln[i]));
puts("");
}
return 0;
}

浙公网安备 33010602011771号