AT_arc086_c Smuggling Marbles(加强版) 题解

第一道长链剖分优化DP。

题目链接

本题解是解决这道题的加强版,在【数据删除】遇到的题目,弹珠上限被加强到了更大的值,但是解法还是类似的。

先看题目,因为是同时传递的物品,因此实际上每一层的结果是独立的,启示我们使用DP。设 \(dp[i][j][k]\) 表示 \(i\) 子树第 \(j\) 层,成功传递的个数为 \(k\) 的方案数。则有以下转移:
\(dp[u][i][min(j+l,k)]=dp[old][i][j]\times dp[v][i-1][l]\),这里要使用\(min(j+l,k)\),是因为物品不是在传递过程中消失的,而是传递完再消失的。

答案如何求是显然的。这个DP的复杂度很明显是过不去的,需要优化。

观察一下,发现第二维的大小与节点深度有关,这启示我们可以使用长链剖分。

小贴士
长链剖分在处理这种关于树的深度时对复杂度的优化是很大的,可以到 O(n)(并没有根号),证明D老师很会证,网上一堆证法。

因此复杂度得到了优化。

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define fi first
#define se second
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
const LL mod = 1e9 + 7;
const int N = 2e5 + 10;
vector<int> G[N];
LL f[N][6];
int top[N],maxdep[N],son[N];
int n,k;
void dfs1(int u){
	maxdep[u] = 1;
	for(int v : G[u]){
		dfs1(v);
		if(son[u] == -1 || maxdep[v] > maxdep[son[u]]) son[u] = v;
	}
	if(son[u] != -1) maxdep[u] = maxdep[son[u]] + 1;
	return ;
}
int tot = 1;
void dfs2(int u){
	for(int i=0;i<k;i++)
		f[top[u]][i] = 1;
	if(son[u] != -1){
		top[son[u]] = top[u] + 1;
		dfs2(son[u]);
	}
	int maxn = 0;
	for(int v : G[u]){
		if(v == son[u]) continue;
		top[v] = tot;
		tot += maxdep[v];
		dfs2(v);
		maxn = max(maxn,maxdep[v]);
		for(int i=1;i<=maxdep[v];i++){
			vector<LL> tmp(k+1,0);
			for(int j=0;j<=k;j++)
				for(int l=0;l<k;l++){
					tmp[min(j+l,k)] += f[top[u]+i][j] * f[top[v]+i-1][l] % mod;
					tmp[min(j+l,k)] %= mod;
				}
			for(int j=0;j<=k;j++)
				f[top[u]+i][j] = tmp[j];
		}
	}
	for(int i=1;i<=maxn;i++){
		f[top[u] + i][0] += f[top[u] + i][k];
		f[top[u] + i][0] %= mod;
		f[top[u] + i][k] = 0;
	}
	return ;
}
LL pre[N],suf[N];
int main()
{
	IOS;
	File("candybarfactory");
	cin >> n >> k;
	for(int i=1;i<=n;i++){
		int x;cin >> x;
		G[x].push_back(i);
	}
	memset(son,-1,sizeof son);
	dfs1(0);
	top[0] = 1;
	tot += maxdep[0];
	dfs2(0);
	pre[0] = 1;
	suf[maxdep[0]+1] = 1;
	for(int i=1;i<=maxdep[0];i++){
		LL s = 0;
		for(int j=0;j<k;j++){
			s += f[i][j];
			s %= mod;
		}
		pre[i] = (pre[i-1] * s)  % mod;
	}
	for(int i=maxdep[0];i>=1;i--){
		LL s = 0;
		for(int j=0;j<k;j++){
			s += f[i][j];
			s %= mod;
		}
		suf[i] = (suf[i+1] * s) % mod;
	}
	LL ans = 0;
	for(int i=1;i<=maxdep[0];i++){
		for(int j=0;j<k;j++){
			ans += pre[i-1] * suf[i+1] % mod * f[i][j] % mod * j % mod;
			ans %= mod;
		}
	}
	cout << ans;
	return 0;
}
posted @ 2026-04-02 09:13  WinterXorSnow  阅读(15)  评论(0)    收藏  举报