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;
}

浙公网安备 33010602011771号