【LOJ】#2542. 「PKUWC2018」随机游走

题解

虽然我知道minmax容斥,但是……神仙能想到把这个dp转化成一个一次函数啊= =

我们相当于求给定的(S)集合里最后一个被访问到的点的时间,对于这样的max的问题,我们可以用容斥把它转化成min问题
也就是

(max{S} = sum_{T subset S} (-1)^{|T| + 1}min{T})

然后我们变成要求对给定的集合,最早访问到其中的点的期望
设当前的点集为(S),(f(u))为从u点出发最早到(S)中的点期望的步数
如果(u in S)
(f(u) = 0)
否则
(f(u) = frac{1}{d[u]}(f(fa[u]) + 1)+ frac{1}{d[u]}sum (f(ch[u]) + 1))
我们发现,从叶子节点开始倒推,我们每个点都可以表示成
(f(u) = A_u f(fa[u]) + B_u)的式子

那么我们把这个式子代进去
(v)代表(u)的儿子
((1 - frac{sum A_{v}}{d[u]})f(u) = frac{1}{d[u]}f(fa[u]) + (1 + frac{sum B_{v}}{d[u]}))
从叶子开始倒退即可,我们把起点当根,那么答案就是起点的(B_x)

最后用FMT累加起来可以做到(O(1))回答询问(也可以子集枚举累加)

复杂度(O(n 2^n + Q))

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#define enter putchar('
')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define MAXN 100005
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 - '0' + c;
	c = getchar();
    }
    res = res * f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
const int MOD = 998244353;
int N,Q,st,A[25],B[25],D[25],cnt,f[(1 << 18) + 5],inv[20];
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
int fpow(int x,int c) {
    int t = x,res = 1;
    while(c) {
	if(c & 1) res = mul(res,t);
	t = mul(t,t);
	c >>= 1;
    }
    return res;
}
struct node {
    int to,next;
}E[105];
int head[20],sumE;
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void dp(int u,int fa,int S) {
    if(S >> (u - 1) & 1) {++cnt;}
    A[u] = B[u] = 0;
    int SumA = 0,SumB = 0;
    for(int i = head[u] ; i ; i = E[i].next) {
	int v = E[i].to;
	if(v != fa) {
	    dp(v,u,S);
	    SumA = inc(SumA,A[v]);
	    SumB = inc(SumB,B[v]);
	}
    }
    if(S >> (u - 1) & 1) return;
    int m = inc(1,MOD - mul(SumA,inv[D[u]]));
    m = fpow(m,MOD - 2);
    int k = inc(1,mul(SumB,inv[D[u]]));
    A[u] = mul(inv[D[u]],m);
    B[u] = mul(k,m);
}
void Solve() {
    read(N);read(Q);read(st);
    int u,v;
    for(int i = 1 ; i < N ; ++i) {
	read(u);read(v);
	add(u,v);add(v,u);
	++D[u];++D[v];
    }
    inv[1] = 1;
    for(int i = 2 ; i <= N ; ++i) {
	inv[i] = mul(inv[MOD % i],(MOD - MOD / i));
    }
    for(int S = 1 ; S < (1 << N) ; ++S) {
	cnt = 0;
	dp(st,0,S);
	if((cnt + 1) & 1) f[S] = MOD - B[st];
	else f[S] = B[st];
	out(f[S]);space;
    }
    enter;
    for(int i = 1 ; i < (1 << N) ; i <<= 1) {
	for(int j = 1 ; j < (1 << N) ; ++j) {
	    if(j & i) f[j] = inc(f[j],f[j ^ i]);
	}
    }
    int k,S;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

颓颓颓颓颓

原文地址:https://www.cnblogs.com/ivorysi/p/9187798.html