P4516 [JSOI2018] 潜入行动题解

前置知识

树形dp,时间复杂度分析(最重要

思路

有一个非常简单的思路,最直接的做法是设 \(dp_{u,i,0/1,0/1}\) 表示树上的第 \(u\) 个节点内,放了 \(i\) 个设备,\(u\) 放没放设备,\(u\) 有没有被监视的方案数。
转移也非常简单对于 \(dp_{i,j}\) 根据后两位分成 \(4\) 种情况讨论。就可以得出一大坨 \(dp\) 式子。

dp[u][i+j][0][0]=(dp[u][i+j][0][0]+tmp[i][0][0]*dp[v][j][0][1]%mod)%mod;
dp[u][i+j][0][1]=(dp[u][i+j][0][1]+(tmp[i][0][1]*(1ll*dp[v][j][0][1]+dp[v][j][1][1])+tmp[i][0][0]*dp[v][j][1][1]%mod)%mod)%mod;				
dp[u][i+j][1][0]=(dp[u][i+j][1][0]+tmp[i][1][0]*((1ll*dp[v][j][0][1]+dp[v][j][0][0])%mod)%mod)%mod;
dp[u][i+j][1][1]=(dp[u][i+j][1][1]+(tmp[i][1][1]*((1ll*dp[v][j][0][0]+dp[v][j][0][1]+dp[v][j][1][0]+dp[v][j][1][1])%mod)%mod+tmp[i][1][0]*(1ll*dp[v][j][1][0]+dp[v][j][1][1]))%mod)%mod;

然后我们反思自己推式子的过程发现不用我们自己来推,可以通过枚举限制直接转移。得到更为简洁的式子。

for(int p1 = 0; p1 < 2; p1 ++)
	for(int q1 = 0; q1 < 2; q1 ++)
		for(int p2 = 0; p2 < 2; p2 ++)
			for(int q2 = 0; q2 < 2; q2 ++)
				if(q2 | p1)
					(newf_u[a + b][p1][q1 | p2] +=
							f[u][a][p1][q1] * f[v][b][p2][q2]) %= mod;

问题的关键在于时间复杂度的证明,直观感受是 \(O(nk^2)\) 但是这样就过不去了,实际情况显然不是这样的,所以说明我们的时间复杂度证明有问题。
1.有两个子树大小大于等于为 \(k\) 的合并,复杂度是 \(k^2\) 的,但是只会出现 \({n\over k}\) 次,所以总的时间复杂度为 \(nk\)
2.
3.对于两个子树大小都小于 \(k\) ,合并起来子树大于 \(k\) ,就是树形背包板经典的时间复杂度分析。对于每一个位置均摊下来是 \(k\) 的。

posted @ 2025-03-25 14:57  exCat  阅读(13)  评论(0)    收藏  举报