美团2021届秋季校园招聘笔试-小美的区域会议——人工加入限制+树形dp
Posted hans774882968
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了美团2021届秋季校园招聘笔试-小美的区域会议——人工加入限制+树形dp相关的知识,希望对你有一定的参考价值。
总结:集合划分的思想+树形dp+定义序关系(用于去重)
直接按树形dp想,没有思路,因为你强行记录所选取方案集合的权值最小和最大显然不可做。
此时考虑加入一些假设(限制)。假设当前枚举的点i
是所选子树的点权最小的点(假设是最大的点也行)。不难发现遍历所有i
对应的合法方案集合,是对所有合法方案的一个划分。以i
为树根跑树形dp,保证所有选择的点的权值都在a[rt]~a[rt]+k
即可。因为子树答案只会被使用一次,所以dp数组可以省略。时间复杂度:O(n^2)
但是我们还面临一个问题:如果一个合法方案有多个最小点权的点,则以上方法会重复统计。因此定义一个序关系(注:在单调栈相关的一些题目里也见过这种技巧,我把它叫做”非对称定义“。):当a[v] == a[rt]
,只有编号小于rt
的那些点v
对应的子树才能被选择。在此定义下,某个合法方案只会被编号最大的那个点权最小的点统计。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
const int N = 2e3 + 5;
const int mod = 1e9 + 7;
int n,k,a[N];vector<int> G[N];
void dbg(){puts("");}
template<typename T, typename... R>void dbg(const T &f, const R &... r) {
cout << f << " ";
dbg(r...);
}
template<typename Type>inline void read(Type &xx){
Type f = 1;char ch;xx = 0;
for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
xx *= f;
}
LL dfs(int u,int ufa,int rt){
LL ans = 1;
for(int v: G[u]){
if(v == ufa) continue;
if((a[v] == a[rt] && v < rt) || (a[rt] < a[v] && a[v] <= a[rt]+k)){
(ans *= (1+dfs(v,u,rt))%mod) %= mod;
}
}
return ans;
}
int main(int argc, char** argv) {
read(n);read(k);
re_(_,1,n){
int p1,p2;read(p1);read(p2);
G[p1].push_back(p2);
G[p2].push_back(p1);
}
rep(i,1,n) read(a[i]);
int ans = 0;
rep(i,1,n) (ans += dfs(i,0,i)) %= mod;
printf("%d\\n",ans);
return 0;
}
以上是关于美团2021届秋季校园招聘笔试-小美的区域会议——人工加入限制+树形dp的主要内容,如果未能解决你的问题,请参考以下文章