首页 > 其他分享 >CF543D 题解

CF543D 题解

时间:2023-05-14 10:22:41浏览次数:54  
标签:pre nxt int 题解 pos CF543D dp mod

前言

题目传送门!

更好的阅读体验?

比较有趣的换根 DP。

思路

First DFS

按照换根 DP 套路,先钦定 \(1\) 为首都(即根节点),并计算。

显然是树形 DP。设 \(dp_{u}\) 表示以 \(u\) 为根的子树全部满足的方案数。

对于一条树边 \((u, v)\):

  • 如果 \((u,v)\) 修,就意味着 \(v\) 对应子树的所有点,还有一次不修的机会,即 \(dp_v\)。
  • 如果 \((u,v)\) 不修,没容错了,下面的全得修,就是 \(1\)。

综上,\(dp_u=\prod\limits_{\text{son}=v} dp_u \times (dp_v+1)\)。

Second DFS

进行换根。

假设当前根为 \(u\)。对于一条树边 \((u, v)\),我们可以换根 \(\text{root}=v\),那么:

  • \(u\) 少了 \(v\) 原本的那个子树。相当于原本答案去除 \((dp_v+1)\) 这个分支,即除法(考虑逆元?)。
  • \(v\) 多了 \(u\) 这个子树。同样的,相当于添加了 \((dp_u+1)\) 这个分支,即乘法。

按照上述转移就做完了。但是!由于 \(0\) 没有逆元,所以直接除不可取。使用前后缀积的方式快速维护,参考代码。

代码

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 2e5 + 5, mod = 1e9 + 7;
struct Edge {int now, nxt;} e[N << 1];
int head[N], cur;
void add(int u, int v)
{
	e[++cur].now = v, e[cur].nxt = head[u];
	head[u] = cur;
}
int dp[N]; //dp[u] : 以u为根的方案数 
//如果(u,v)修,就是 dp[v]:如果(u,v)不修,下面的全得修,就是1。dp[u]=prod dp[u] * (dp[v]+1)
void dfs(int u, int fa)
{
	dp[u] = 1;
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].now;
		if (v == fa) continue;
		dfs(v, u), dp[u] = 1ll * dp[u] * (dp[v] + 1) % mod;
	}
}
#define update(x) pre.push_back(x + 1), suf.push_back(x + 1)
void DFS(int u, int fa, int mulfa)
{
	vector <int> pre, suf;
	for (int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].now;
		if (v == fa) {if (mulfa != -1) update(mulfa);}
		else update(dp[v]);
	}
	int siz = pre.size();
	
	#define lst(i) (i == 0 ? 1 : pre[i - 1])
	#define nxt(i) (i == siz - 1 ? 1 : suf[i + 1])
	for (int i = 0; i < siz; i++) pre[i] = 1ll * pre[i] * lst(i) % mod;
	for (int i = siz - 1; ~i; i--) suf[i] = 1ll * suf[i] * nxt(i) % mod;
	
	for (int i = head[u], pos = 0; i; i = e[i].nxt, pos++)
	{
		int v = e[i].now;
		if (v == fa) continue;
		int tmp = 1ll * lst(pos) * nxt(pos) % mod;
		dp[v] = 1ll * dp[v] * (tmp + 1) % mod, DFS(v, u, tmp);
	}
}
int main()
{
	int n;
	scanf("%d", &n);
	for (int i = 2; i <= n; i++)
	{
		int u;
		scanf("%d", &u);
		add(i, u), add(u, i);
	}
	dfs(1, 0), DFS(1, 0, -1);
	for (int i = 1; i <= n; i++) printf("%d ", dp[i]);
	return 0;
}

希望能帮助到大家!

标签:pre,nxt,int,题解,pos,CF543D,dp,mod
From: https://www.cnblogs.com/liangbowen/p/17398821.html

相关文章

  • ABC254F 题解
    前言题目传送门!更好的阅读体验?这题trick就是更相减损术:\(\gcd\{a_1,a_2,a_3,\cdots,a_n\}=\gcd\{a_1,a_2-a_1,a_3-a_2,\cdots,a_n-a_{n-1}\}\)。思路有了这个trick之后这题就好做了。并不需要其他题解一样画表格,化简式子就行,过程并没有难点。\[\begin{a......
  • UVA12096 题解
    这道题虽然被评黄,但个人感觉不止普及组难度,而且是一道很有价值的题目。题解区里全是\(O(n^2logn)\)的STL大法,我来发一篇\(O(n^2)\)哈希做法。目前0ms喜提最优解。这道题是codeforcesgym的题目,本质上就是模拟栈中集合插入,复制,相加,取交集,取并集的过程。注意,这些集合都是......
  • [AGC001E] BBQ Hard题解
    Problem[AGC001E]BBQHard计算:\[\sum_{i=1}^{n}\sum_{j=i+1}^n\binom{a_i+b_i+a_j+b_j}{a_i+a_j}\]其中\(n\leq2\times10^5\),\(a_i,b_i\leq2000\)Solution以\(a_i\)代\(a_i+b_i\)则等价于求\[\sum_{i=1}^{n}\sum_{j=i+1}^n\binom{a_i+a_j}{b_i+b_j}......
  • 【题解】Luogu[P3750] [六省联考 2017] 分手是祝愿
    Link→小清新dp题,纪念自己的700ac(一个点只有两个状态开和不开,且按两下相当于没按,我们可以从大到小有亮的就按一下,如果我们按到了不需要按的键,就需要再按一下使他变回来。设\(f_i\)表示\(i\)个正确选择变为\(i-1\)个的期望操作次数。则有\(\dfrac{i}{n}\)概率按到......
  • 【题解】Luogu[P4900] 食堂
    一到推柿子题。题意即求\(\sum\limits^{n}_{i=1}\sum\limits^{i}_{j=1}\left\{\frac{i}{j}\bmodP\right\}\)对于\(\frac{i}{j}\bmodP\)我们知道即为\(i\)乘上\(j\)的逆元,即为\(i\cdot\mathrm{inv}(j)\)故:\[\begin{aligned}\sum^{n}_{i=1}\sum^{i}_{j=1}\l......
  • 【题解】Luogu[P6003] USACO20JAN Loan Repayment S
    模拟赛第一题(9pts考虑暴力。枚举\(x\),对于每个\(x\),模拟\(k\)天,判断其是否合法,找出最大的\(x\)。时间复杂度:\(O(n^2)\)36pts考虑优化先前暴力算法。我们不难发现当\(x\)合法时,必然有合法\(x_1\),当且仅当\(x_1<x\)。故\(x\)具有单调性,考虑二分答案。对于\(x......
  • 【题解】Luogu[P8818] CSP-S 2022 策略游戏
    一道简单区间rmq分类讨论题,考场上最后5分钟想出来,没写出来,退役了……给定两个序列\(A_{1},\dots,A_{n}\);\(B_1,\dots,B_n\)规定\(C_{i,j}=A_i\timesB_i\)。题目说小L和小Q必定选择最优策略,而小L先选,小Q后选,小L要使得\(C_{i,j}\)尽可能大,小Q要使得\(C_{i,j}\)......
  • 【题解】Luogu[P1879] [USACO06NOV]Corn Fields G
    Link→状压dp典题,看数据范围就能多半猜到是状压。\(M\)行\(N\)列很不舒服,本篇题解规定为\(N\)行\(M\)列。因为说没有哪两块草地相连,我们不妨一行一行考虑,一行中每格只可能是\(0\)或\(1\),所以一行的总不同状态数是\(2^M\)。我们用二进制表示每一行的状态,对于每一行,暴......
  • 【题解】Luogu[P1967] NOIP2013 提高组 货车运输
    Link→很容易想到一个暴力做法,就是跑一遍Floyd,\(F_{i,j}\)表示\(i\)到\(j\)最大载重量,转移\(F_{i,j}=\max\{F_{i,j},\min\{F_{i,k},F_{k,j}\}\}\)。显然时间复杂度\(O(n^3)\)是过不了的。我们发现,因为是求两点路径中使得最小值最大,实际上有一些较小的路径是不会走......
  • CF1698F题解
    考虑一个函数\(f(a)\),它的返回值是一个二维数组\(b\),接受值是一个数组\(a\)。对于所有\(i=1\ton-1\)的\(i\),把\(b_{a_i}{a_{i+1}}++\),然后返回\(b\)。\(f(a)!=f(b)\)且\(a_1=b_1,a_n=b_n\)是无解的充要条件,因为显然对于数组的每次翻转操作它的\(f\)返回值都不会变。\(f(a)!=f(b......