【2021集训队出题】愚蠢的在线法官

【2021集训队出题】愚蠢的在线法官

by AmanoKumiko

Description

给出一颗n个点的树,再给出每个点的权值v

然后给出一个长度为k的数组A

然后对于kk的矩阵,i,j[1,k]Vi,j=vlca(Ai,Aj),求它的行列式

Input

第一行两个整数n,k

第二行n个数,表示权值

第三行k个数表示A

接下来n1行,读入一颗树

Output

一行一个数表示答案对998244353取模的结果

Sample Input

3 2
1 2 3
2 3
1 2
1 3

Sample Output

5

Data Constraint

1n,k5105,vi[0,998244353),Ai[1,n]

Solution

一些高代:

1.行列式交换两行取反

2.行列式中某一行提出一个公因子x,行列式乘上x

3.行列式中某一行中ai都表示成bi+ci的形式,那么行列式等于取bici情况下的和

4.行列式中两行相减,行列式不变

首先,如果A中存在相等的数,答案是0

然后我们考虑树形dp

fi表示以i为根的子树的行列式

考虑加入一个子树时的贡献

那么变成这种形式

|ABCD|

A是原答案,D是子树的答案

x=vu,那么B,C均为x

我们直接给一行减去x

然后变成了

x|1111aa0000aa00aa|

|aaxxaaxxxxaa00aa|

的形式

对于前者,我们引入一个gi表示在i的行列式中,将某一行全部变成1的答案

对于后者,我们可以继续让别的行减去x,最后变为

|aa00aa0000aa00aa|

再令s=vson(u)fv

那么有fu=vson(u)gvxsfv+s

而在这种情况下,

后代求的行列式实际上是后代所有v减去当前v的行列式,这个随便处理一下就可以了

对于g的递推,类似

然后再特判一下当前点在A中的情况就行了

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define Fs(i,a) for(int i=last[a];i;i=e[i].next)
#define LL long long
#define mo 998244353
#define N 500010

int n,k,a,b,A[N],vis[N],tot,last[N];
LL v[N],f[N],g[N],tag;

struct node{int en,next;}e[N*2];

void add(int x,int y){e[++tot]=(node){y,last[x]};last[x]=tot;}

LL mi(LL x,LL y){
	if(y==1)return x;
	return y%2?x*mi(x*x%mo,y/2)%mo:mi(x*x%mo,y/2);
}

void dfs(int now,int pre){
	v[now]=(v[now]-tag+mo)%mo;
	(tag+=v[now])%=mo;
	LL fs=1;int s=0;
	Fs(i,now)if(e[i].en!=pre)dfs(e[i].en,now),fs=fs*f[e[i].en]%mo,s++;
	if(vis[now]){
		if(!s)f[now]=v[now],g[now]=1;
		else f[now]=fs*v[now]%mo,g[now]=fs;
	}else{
		f[now]=fs;
		Fs(i,now)if(e[i].en!=pre){
			LL x=mi(f[e[i].en],mo-2);
			(f[now]+=fs*x%mo*g[e[i].en]%mo*v[now]%mo)%=mo;
			(g[now]+=fs*x%mo*g[e[i].en]%mo)%=mo;
		}
	}
	tag=(tag-v[now]+mo)%mo;
}

int main(){
	scanf("%d%d",&n,&k);
	F(i,1,n)scanf("%lld",&v[i]);
	F(i,1,k){
		scanf("%d",&A[i]);
		if(vis[A[i]]){printf("0");return 0;}
		vis[A[i]]=1;
	}
	F(i,1,n-1)scanf("%d%d",&a,&b),add(a,b),add(b,a);
	dfs(1,0);
	printf("%lld",f[1]);
	return 0;
}
posted @   冰雾  阅读(211)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示