zoukankan      html  css  js  c++  java
  • [PKUWC2018]随机游走

    Sol

    题目需要求访问完所有点(假设有 (n) 个)的期望步数,也就是要求

    [E(max{x_1,x_2,cdots,x_n}) ]

    这里 (x_1)(x_2)(cdots)(x_n) 表示第一次到达对应编号的关键点的时间。

    根据 Min-Max 容斥,有

    [E(max{S})=E(max{x_1,x_2,cdots,x_n})=Eleft(sum_{S'subseteq S}(-1)^{|S'|-1}min{S'} ight)=sum_{S'subseteq S}(-1)^{|S'|+1}E(min{S'})(S' ephi) ]

    最后一步等号根据期望的线性性。

    对于某一个集合 (S),设 (f_u) 表示从节点 (u) 开始,第一次到达 任意 给定点期望步数。根据期望 DP:当 (uin S)

    [f_u=0 ]

    (u otin S)

    [f_u=frac1{deg_u}left(f_{fa_u}+sum_{vin son_u}f_v ight)+1 ]

    直接高斯消元复杂度很劣。注意到这是一棵树。

    根据线性代数的知识,使用待定系数法。令 (f_u=k_uf_{fa_u}+b_u),转化下原式

    [egin{aligned} &f_u=frac1{deg_u}left(f_{fa_u}+sum_{vin son_u}k_vf_u+b_v ight)+1\ &Rightarrow deg_uf_u=f_{fa_u}+f_usum_{vin son_u}k_v+sum_{vin son_u}b_v+deg_u\ &Rightarrow f_uleft(deg_u-sum_{vin son_u}k_v ight)=f_{fa_u}+sum_{vin son_u}b_v+deg_u\ &Rightarrow f_u=frac1{deg_u-sum_{vin son_u}k_v}f_{fa_u}+frac{deg_u+sum_{vin son_u}b_v}{deg_u-sum_{vin son_u}k_v} end{aligned} ]

    因此有

    [egin{cases} egin{aligned} k_u&=frac1{deg_u-sum_{vin son_u}k_v}\ b_u&=frac{deg_u+sum_{vin son_u}b_v}{deg_u-sum_{vin son_u}k_v} end{aligned} end{cases} ]

    (u in S) 时,(k_u=b_u=0)

    可以使用 DP 求系数。由于本题的特殊性((n) 很小,或者题目有保证),不存在分母为模数的倍数的情况。故求出系数,复杂度为 (mathcal O(nlog P)),注意要求逆元。总共要求 (2^n) 种情况,故复杂度为 (mathcal O(n2^nlog P))

    预处理所有询问,发现实际上是一个子集枚举,使用 FWT 优化即可。注意系数。这部分复杂度 (mathcal O(n2^n))。总复杂度为 (mathcal O(n2^nlog P))

    Code

    #include <bits/stdc++.h>
    const int N = 19, P = 998244353;
    int n, Q, x;
    struct Edge { int v, nxt; } e[N * 2];
    int G[N], edges = 0;
    void adde(int u, int v) {
    	e[edges++] = (Edge){v, G[u]}; G[u] = edges - 1;
    }
    int inc(int a, int b) { return (a += b) >= P ? a - P : a; }
    int qpow(int a, int b) {
    	int t = 1;
    	for (; b; b >>= 1, a = 1LL * a * a % P)
    		if (b & 1) t = 1LL * t * a % P;
    	return t;
    }
    int k[N], b[N];
    void dfs(int u, int f, int S) {
    	if (S & (1 << u-1)) { k[u] = b[u] = 0; return; }
    	int deg = f ? 1 : 0, K = 0, B = 0;
    	for (int i = G[u], v; ~i; i = e[i].nxt)
    		if (v = e[i].v, v != f)
    			dfs(v, u, S), deg++, K = inc(K, k[v]), B = inc(B, b[v]);
    	k[u] = qpow(inc(deg, P - K), P - 2);
    	b[u] = 1LL * k[u] * (deg + B) % P;
    }
    int a[1 << N];
    void fwt(int *a, int n, int op) {
    	for (int q = 1; q < n; q <<= 1)
    		for (int p = 0; p < n; p += q << 1)
    			for (int i = 0; i < q; i++)
    				a[p+q+i] = inc(a[p+q+i], a[p+i]);
    }
    int main() {
    	scanf("%d%d%d", &n, &Q, &x);
    	memset(G, -1, sizeof G);
    	for (int i = 1; i < n; i++) {
    		int u, v; scanf("%d%d", &u, &v);
    		adde(u, v), adde(v, u);
    	}
    	for (int S = 1; S < 1 << n; S++) {
    		int cnt = 0;
    		dfs(x, 0, S);
    		for (int i = 0; i < n; i++) cnt += (S >> i) & 1;
    		a[S] = cnt & 1 ? b[x] : P - b[x];
    	}
    	fwt(a, 1 << n, 1);
    	while (Q--) {
    		int k, S = 0; scanf("%d", &k);
    		for (int i = 1; i <= k; i++)
    			scanf("%d", &x), S |= 1 << x-1;
    		printf("%d
    ", a[S]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    SAP S/4HANA extensibility扩展原理介绍
    SAP CRM系统订单模型的设计与实现
    使用nodejs代码在SAP C4C里创建Individual customer
    SAP Cloud for Customer Account和individual customer的区别
    Let the Balloon Rise map一个数组
    How Many Tables 简单并查集
    Heap Operations 优先队列
    Arpa’s obvious problem and Mehrdad’s terrible solution 思维
    Passing the Message 单调栈两次
    The Suspects 并查集
  • 原文地址:https://www.cnblogs.com/ac-evil/p/14466726.html
Copyright © 2011-2022 走看看