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;
}
posted @ 2026-01-12 17:13  yemuzhe  阅读(1)  评论(0)    收藏  举报