LOJ #2542. 「PKUWC 2018」随机游走(最值反演 + 树上期望dp)

题目:点击打开链接

题解:点击打开链接

关键:minmax反演。求max转化为求子集的min和

        求min时期望dp转移时递推系数即可

        对询问记忆化不用枚举子集,好像有个n*2^n的优化 先留坑

#include<bits/stdc++.h>
using namespace std;
#define maxn 500020
#define lowbit(x) (x&(-x))

typedef long long ll;
const ll p = 998244353;
struct node{
	int next,to;
}e[50];
int head[maxn],cnt;
int n,q,x,fa[50],N,deg[50],sz[maxn],vis[maxn];
ll mn[maxn],g[50],mx[maxn],A[22],B[22];

inline void adde(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
void dfs(int x){
	for (int i = head[x] ; i ; i = e[i].next){
		if ( e[i].to == fa[x] ) continue;
		fa[e[i].to] = x;
		dfs(e[i].to);
	}
}
inline ll power(ll x,int y){
	ll res = 1;
	while ( y ){
		if ( y & 1 ) res = res * x % p;
		x = x * x % p;
		y >>= 1;
	}
	return res;
}
inline void Add(ll &x,ll y){
	 x += y;
	 if ( x >= p ) x -= p;
	 else if ( x < 0 ) x += p;
}
void DP(int x,int S){
	if ( S & (1 << (x - 1)) ){ A[x] = B[x] = 0; return; }
	ll totA = 0 , totB = 0 , inv;
	for (register int i = head[x] ; i ; i = e[i].next){
		if ( e[i].to == fa[x] ) continue;
		DP(e[i].to,S);
		Add(totA,A[e[i].to]) , Add(totB,B[e[i].to]);
	}
	inv = power(deg[x] - totA,p - 2);
	A[x] = inv , B[x] = (totB + deg[x]) * inv % p;
}
void init(){
	dfs(x);
	N = 1 << n;
	for (int i = 1 ; i < N ; i++){
		if ( i & (1 << (x - 1)) ) mn[i] = 0;
		else{
			memset(A,0,sizeof(A)) , memset(B,0,sizeof(B));
			DP(x,i);
			mn[i] = B[x];
		}
		sz[i] = sz[i ^ lowbit(i)] + 1;
	}
/*	for (int i = 1 ; i < N ; i++){
		for (register int j = i ; j ; j = (j - 1) & i){
			if ( sz[j] & 1 ) Add(mx[i],mn[j]);
			else Add(mx[i],-mn[j]);
		}
	}*/
}
int main(){
	scanf("%d %d %d",&n,&q,&x);
	for (int i = 1 ; i < n ; i++){
		int x,y;
		scanf("%d %d",&x,&y);
		adde(x,y) , adde(y,x);
		deg[x]++ , deg[y]++;
	}
	init();
	while ( q-- ){
		int k,cur = 0,x = 0; scanf("%d",&k);
		while ( k-- ) scanf("%d",&x) , cur |= 1 << (x - 1);
		if ( !vis[cur] ){
			for (register int j = cur ; j ; j = (j - 1) & cur){
				if ( sz[j] & 1 ) Add(mx[cur],mn[j]);
				else Add(mx[cur],-mn[j]);
			}
			vis[cur] = 1;
		}
		printf("%lld\n",mx[cur]);
	}
	return 0;
}



猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/80914108
今日推荐