namomo week1
Posted XINNNNNNNYU
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了namomo week1相关的知识,希望对你有一定的参考价值。
题单
A - Crystalfly
题意
给你一棵树,每个点上有a[i]个蝴蝶,当你走到u点,与u相邻的v的蝴蝶会在t[v]秒之后被惊动逃走(但是v的儿子不会被惊动),问你最多能抓到几只蝴蝶。
思路
可以注意到t数组的范围是1<= t <= 3,我们跟据t把u的儿子分为三类。第一秒可以选三类中的任意一个,第二秒可以选择继续走第一秒选择的儿子,或者是回到u,但是此时第三秒只能走t=3的那个儿子了(一来一回过去了2秒,t小于3的蝴蝶都被惊动飞走了,而往第一秒选择的儿子走显然不是最优)。
这两类行走方案如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fCoH09r9-1670481473128)(/upload/2022/02/image-a2f2948ff89345e8a3e1429c4135acb8.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MEPE6XdI-1670481473129)(/upload/2022/02/image-5b2d036624f841cc9af43222cd206d8b.png)]
我们先不管根结点u抓不抓得到
定义
- dp[i][0]代表i不选并且所有儿子已经不能再抓了的最大值(就是两种路线取最大值)
- dp[i][1]代表i选并且所有儿子已经不能再抓了的最大值
- dp[i][2]代表i不选并且所有儿子都不选且已经不能再抓了的最大值
- 第一张图
- 我们选择第一个儿子,其他儿子都不选,所以dp[u][0] = sumdp[son][0] 加上a最大的一个儿子
- dp[u][2]相比于此时的dp[u][0]差别在于少加一个a最大的儿子
- 第二张图
- 我们枚举那些可以二次拯救的点(即t=3的点),假设所有点的贡献都是dp[i][0],就是sumdp[son][0],就是dp[u][2],然后拯救的点(第三步走的点)j的a[j]可以加上。对于每个点v变成第一步走的点贡献变化是a[v] + dp[v][2] - dp[v][0],显然我们要选变化最大的点走第一步,但是这个点可能和我们枚举的拯救的点是同一点,所以我们要记录变化前二大的点(判断点是否是同一个点,所以还要记录点的编号)。
- 由此dp[u][0] = max(dp[u][0],dp[u][2] + a[j] + (c[0].second == j ? c[1].first : c[0].first))
最后dp[u][1] = dp[u][0] + a[u]
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\\n'
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
#define debug(args...) string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args);
void err(istream_iterator<string> it)
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args)
cerr << *it << " = " << a << endl;
err(++it, args...);
int qmi(int a, int k, int p)int res = 1;while (k)if (k & 1) res = (ll)res * a % p;a = (ll)a * a % p;k >>= 1;return res;
int qpow(int a,int b)int res = 1;while(b)if(b&1) res *= a;b>>=1;a*=a;return res;
int mo(int x,int p)return x = ((x%p)+p)%p;
int gcd(int a,int b)return b?gcd(b,a%b):a;
const int maxn = 1e6+7;
const int mod = 1e9+7;
const double eps = 1e-6;
const int INF = 0x3f3f3f3f3f3f3f3f;
int dx[] = 0,0,1,-1, dy[] = 1,-1,0,0;
int T = 1,N,M,K,Q;
int e[maxn],w[maxn],ne[maxn],h[maxn],idx;
void add(int a, int b)
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
void add(int a, int b, int c)
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
vector<int> a(maxn),t(maxn);
vector<vector<int>> dp(3,vector<int>(maxn));
void dfs(int u, int fa)
dp[0][u] = 0;
int max_son = 0;
int son_num = 0;
vector<pair<int, int> > c = make_pair(-1e18,0ll), make_pair(-1e18,0ll),make_pair(-1e18,0ll);
for (int i = h[u]; ~i; i = ne[i])
int j = e[i];
if (j == fa) continue;
son_num++;
dfs(j, u);
max_son = max(max_son, a[j]);
dp[0][u] += dp[0][j];
c[2] = make_pair(a[j] + dp[2][j] - dp[0][j],j);
sort(c.begin(),c.end(),[&](pair<int, int> aa, pair<int, int> bb)
if (aa.first != bb.first)
return aa.first > bb.first;
else
return aa.second < bb.second;
);
int temp = dp[0][u];
dp[2][u] = dp[0][u];
dp[0][u] = dp[0][u] + max_son;//找个最大儿子进,其他县摆烂
// if (son_num > 1)
for (int i = h[u]; ~i; i = ne[i])
int j = e[i];
if (j == fa || t[j] != 3) continue;
//回首套的点
dp[0][u] = max(dp[0][u], temp + a[j] + (c[0].second == j ? c[1].first : c[0].first));
//
dp[1][u] = dp[0][u] + a[u];
void solve()
cin >> N;
idx = 0;
memset(h,-1,sizeof(int)*(N+10));
for (int i = 1; i <= N; i ++) cin >> a[i];
for (int i = 1; i <= N; i ++) cin >> t[i];
for (int i = 1; i < N; i ++)
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
dfs(1, -1);
cout << dp[1][1] << endl;
signed main()
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
for (int i = 1; i <= T; i ++) solve();
return (0-0); //<3
B - Towers
题意
给你一棵树,每个点的权值为a[i],现在要求你给每个点的e[i]赋值,使得每个点都存在两个点u,v,这个点在u,v的简单路径上,且e[u]>=a[i]且e[v]>=a[i]。求所有e[i]的和(e[i] >= 0)
思路
我们首先找到权值最大的点root,以它为根。因为根最大,肯定有两个点的e是a[root]是专门用来满足root的。这样对于除了根以外的所有点i都可以从上述两个点其中一个到根再到i,这样来获得u,v的其中一个。而另一个一定是在i的子树当中(包括i本身)。如果子树的最大值大于等于a[i]了,那么e[i]=0,不需要额外开销;如果子树的最大值小于a[i],我们则需要把最大值补成a[i],开销是a[i]-max。
因为要先知道子树中的最大值,所以我们先递归到叶子结点,在回溯时从下往上处理。
当回溯到根的时候,因为我们一开始是设了两个点的e等于a[root]的,他们应该在root不同的儿子里,要不然就不是简单路径了。所以我们把root的每个儿子的子树的最大值存起来,取前两个大的补成a[root]。
但是root可能只有一个儿子,那么我们只需要把e[root]设为a[root]
代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define int long long
#define endl "\\n"
#define error(args...) string _s = #args; replace(_s.begin(), _s.end(), ',', ' '); stringstream _ss(_s); istream_iterator<string> _it(_ss); err(_it, args);
void err(istream_iterator<string> it)
template<typename T, typename... Args>
void err(istream_iterator<string> it, T a, Args... args)
cerr << *it << " = " << a << endl;
err(++it, args...);
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
int qmi(int a, int k, int p)int res = 1;while (k)if (k & 1) res = (ll)res * a % p;a = (ll)a * a % p;k >>= 1;return res;
int qpow(int a,int b)int res = 1;while(b)if(b&1) res *= a;b>>=1;a*=a;return res;
int mo(int x,int p)return x = ((x%p)+p)%p;
int gcd(int a,int b)return b?gcd(b,a%b):a;
const int maxn = 1e6+7;
const int mod = 1e9+7;
const double eps = 1e-6;
int dx[] = 0,0,1,-1, dy[] = 1,-1,0,0;
int T = 1,N,M,K,Q;
int e[maxn],w[maxn],ne[maxn],h[maxn],idx;
void add(int a, int b)
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
void add(int a, int b, int c)
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
int ans = 0;
int root = 1;
vector<int> a(maxn);
int dfs(int u, int fa)
int mx = 0;
vector<int> mmax;
for (int i = h[u]; ~i; i = ne[i])
int j = e[i];
if (j == fa) continue;
int t = dfs(j, u);
mx = max(mx, t);
if (u == root)
mmax.push_back(-t);
if (u == root)
sort(mmax.begin(),mmax.end());
ans += max(0ll,a[root] + mmax[0]);
if (mmax.size() < 2)
ans += a[root];
else ans += max(0ll,a[root] + mmax[1]);
return 0;
if (mx < a[u])
ans += a[u] - mx;
mx = a[u];
return mx;
void solve()
cin >> N;
memset(h,-1,sizeof(int)*(N+10));
for (int i = 1; i <= N; i ++) cin >> a[i];
for (int i = 1; i < N; i ++)
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
for (int i = 2; i <= N; i ++)
if (a[i] > a[root]Namomo Spring Camp 2022 Div2 Week1 每日一题
Namomo Spring Camp 2022 Div1 XOR Inverse Codeforces Round #673 (Div. 1) C. XOR Inverse 按位贪心模拟/字典树分治
Namomo Spring Camp 2022 Div1 XOR Inverse Codeforces Round #673 (Div. 1) C. XOR Inverse 按位贪心模拟/字典树分治
Namomo Spring Camp 2022 Div1 XOR Inverse Codeforces Round #673 (Div. 1) C. XOR Inverse 按位贪心模拟/字典树分治