题解 park/chase
这题考试的时候觉得时间复杂度假了,\(n \geqslant 1000\)的部分直接瞎写了个特殊性质上去,结果假的时间复杂度能有60pts……
- 比较大的数组无论如何不要直接全部memset!如果在写部分分,考虑用多少memset多少
memset真的可以把一份74pts代码卡成30pts的 memset一个1e9的int数组要0.2s long long要0.7s
首先70pts可以枚举起点,每次跑一遍dfs
令 \(g[i][j]\) 表示以 \(i\) 为起点,撒 \(j\) 次面包屑得到的最大收益即可
这部分代码:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, V;
int p[N], head[N], size;
struct edge{int to, next; bool vis;}e[N<<1];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}
namespace force{
ll ans;
bool none[N];
void dfs(int u, int fa, int v2, ll sum) {
if (v2<=0) {ans=max(ans, sum); return ;}
bool cge=0;
if (!none[u]) none[u]=1, cge=1;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v!=fa) dfs(v, u, v2, sum);
}
for (int i=head[u],v; i; i=e[i].next) if (!none[e[i].to]) {sum+=p[e[i].to]; none[e[i].to]=1; e[i].vis=1;}
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v!=fa) dfs(v, u, v2-1, sum);
}
for (int i=head[u],v; i; i=e[i].next) if (e[i].vis) {e[i].vis=0; none[e[i].to]=0;}
if (cge) none[u]=0;
}
void solve() {
//for (int i=1; i<=n; ++i) {
//memset(none, 0, sizeof(none));
dfs(1, 0, V, 0);
//}
printf("%lld\n", ans);
exit(0);
}
}
namespace task1{
ll dp[N][105][4], ans;
//ll allcnt;
void dfs(int u, int fa) {
//cout<<"dfs "<<u<<' '<<fa<<endl;
ll sum=0;
bool leaf=1;
for (int i=head[u]; i; i=e[i].next) {
sum+=p[e[i].to];
if (e[i].to!=fa) leaf=0;
}
memset(dp[u], 0, sizeof(ll)*420);
dp[u][V][3]=p[fa];
if (leaf) return ;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v!=fa) {
dfs(v, u);
for (int s=V; s>=0; --s) {
//++allcnt;
//dp[u][s][0]=dp[u][s][1]=dp[u][s][2]=dp[u][s][3]=0;
dp[u][s][0] = max(dp[u][s][0], max(dp[v][s+1][2], dp[v][s+1][3]));
dp[u][s][1] = max(dp[u][s][1], max(dp[v][s][0], dp[v][s][1]));
if (s>0) {
dp[u][s][2] = max(dp[u][s][2], sum-p[v]+max(dp[v][s+1][2], dp[v][s+1][3]));
dp[u][s][3] = max(max(dp[u][s][3], sum-p[v]+max(dp[v][s][0], dp[v][s][1])), sum);
}
}
}
}
}
void solve() {
//cout<<double(sizeof(dp))/1024/1024<<endl;
for (int i=1; i<=n; ++i) {
//cout<<i<<endl;
if (clock()>=1600000) {printf("%lld\n", ans); exit(0);}
//memset(dp, 0, sizeof(dp));
dfs(i, 0);
for (int j=0; j<=V; ++j) ans=max(ans, max(max(dp[i][j][0], dp[i][j][1]), max(dp[i][j][2], dp[i][j][3])));
}
//int rt=2;
//dfs(rt, 0);
//for (int j=0; j<=V; ++j) ans=max(ans, max(max(dp[rt][j][0], dp[rt][j][1]), max(dp[rt][j][2], dp[rt][j][3])));
#if 0
for (int i=1; i<=n; ++i) {
for (int j=0; j<=V; ++j) {
for (int k=0; k<4; ++k) cout<<dp[i][j][k]<<' '; cout<<endl;
}
}
#endif
//for (int j=0; j<=V; ++j) {for (int k=0; k<4; ++k) cout<<dp[2][j][k]<<' '; cout<<endl;}
printf("%lld\n", ans);
//cout<<"allcnt: "<<allcnt<<endl;
exit(0);
}
}
namespace task2{
ll f[N][105], g[N][105], ans;
void dfs(int u, int fa) {
//cout<<"dfs "<<u<<' '<<fa<<endl;
ll sum=0;
for (int i=head[u]; i; i=e[i].next) sum+=p[e[i].to];
memset(f[u], 0, sizeof(ll)*105);
f[u][1]=sum;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
memset(g[v], 0, sizeof(ll)*105);
//for (int j=1; j<=V; ++j) {
// g[v][j] = max(g[v][j], max(g[u][j], sum-p[fa]+g[u][j-1]));
//}
dfs(v, u);
for (int j=1; j<=V; ++j) {
//f[u][j] = max(f[u][j], max(f[v][j], sum-p[v]+f[v][j-1]));
g[u][j] = max(g[u][j], max(g[v][j], sum-p[fa]+g[v][j+1]));
}
}
}
void solve() {
for (int i=1; i<=n; ++i) {
if (clock()>=1600000) {printf("%lld\n", ans); exit(0);}
memset(g[i], 0, sizeof(ll)*105);
dfs(i, 0);
for (int j=1; j<=n; ++j) for (int k=0; k<=V; ++k) ans=max(ans, max(f[j][k], g[j][k]));
//for (int j=0; j<=V; ++j) cout<<g[3][j]<<' '; cout<<endl;
}
printf("%lld\n", ans);
exit(0);
}
}
namespace task{
ll f[N][105], g[N][105], ans;
void dfs(int u, int fa) {
//cout<<"dfs "<<u<<' '<<fa<<endl;
ll sum=0;
for (int i=head[u]; i; i=e[i].next) sum+=p[e[i].to];
f[u][1]=sum;
ll maxn[105][4], maxi[105][4];
memset(maxn, 0, sizeof(maxn));
memset(maxi, 0, sizeof(maxi));
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
for (int j=1; j<=V; ++j) {
g[v][j] = max(g[v][j], max(g[u][j], sum-p[fa]+g[u][j-1]));
if (g[v][j]>=maxn[j][0]) {maxn[j][1]=maxn[j][0]; maxi[j][1]=maxi[j][0]; maxn[j][0]=g[v][j]; maxi[j][0]=v;}
else if (g[v][j]>maxn[j][1]) maxn[j][1]=g[v][j], maxi[j][1]=v;
}
dfs(v, u);
for (int j=1; j<=V; ++j) {
f[u][j] = max(f[u][j], max(f[v][j], sum-p[v]+f[v][j-1]));
if (f[v][j]>=maxn[j][2]) {maxn[j][3]=maxn[j][2]; maxi[j][3]=maxi[j][2]; maxn[j][2]=f[v][j]; maxi[j][2]=v;}
else if (f[v][j]>maxn[j][3]) maxn[j][3]=f[v][j], maxi[j][3]=v;
}
}
cout<<"u: "<<u<<endl;
for (int j=0; j<V; ++j) {
if (maxi[j+1][0]!=maxi[j][2]) ans=max(ans, maxn[j+1][0]+maxn[j][2]), cout<<"try1: "<<maxn[j+1][0]<<' '<<maxi[j+1][0]<<' '<<maxn[j][2]<<' '<<maxi[j][2]<<' '<<maxn[j+1][0]+maxn[j][2]<<endl;
else {
if (maxi[j+1][1]!=maxi[j][2]) ans=max(ans, maxn[j+1][1]+maxn[j][2]), cout<<"try2: "<<maxn[j+1][1]<<' '<<maxi[j+1][1]<<' '<<maxn[j][2]<<' '<<maxi[j][2]<<' '<<maxn[j+1][1]+maxn[j][2]<<endl;
if (maxi[j+1][0]!=maxi[j][3]) ans=max(ans, maxn[j+1][0]+maxn[j][3]), cout<<"try3: "<<maxn[j+1][0]<<' '<<maxn[j][3]<<' '<<maxn[j+1][0]+maxn[j][3]<<endl;
}
ans=max(ans, max(maxn[j][0], maxn[j][2]));
}
}
void solve() {
dfs(1, 0);
printf("%lld\n", ans);
exit(0);
}
}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
n=read(); V=read();
for (int i=1; i<=n; ++i) p[i]=read();
for (int i=1,u,v; i<n; ++i) {
u=read(); v=read();
add(u, v); add(v, u);
}
task2::solve();
return 0;
}
然后考虑如何不枚举起点
那就需要换根DP了,令 \(f[i][j]\) 表示从以i为根的子树中走到 \(i\) ,$ g[i][j]$ 表示从i的父亲走到 \(i\) 及其子树中撒 \(j\) 次的最大收益
转移的时候要特别注意先后顺序
首先方程有了,ans=max(ans, f[u][j]+g[to][v-j])
而我们要在同一次遍历中更新 \(ans,f[u][j],g[u][j]\)
因为f和g肯定不能选来自同一棵子树的,所以f要用从之前遍历过的子树中的,所以先更新ans,再转移f,g
发现这样只是在用一个g匹配它左边的所有f,显然不够,所以还要逆序枚举一遍
挺有思维量的,做了巨久……还因为变量名重了没看出来陷入高度自闭
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, v;
int head[N], size, sta[N], top; ll p[N], sum[N], ans, f[N][105], g[N][105];
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}
void dfs(int u, int fa) {
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
sum[u]+=p[v];
if (v!=fa) dfs(v, u);
}
int to;
for (int i=1; i<=v; ++i) f[u][i]=sum[u], g[u][i]=sum[u]-p[fa];
for (int i=head[u]; i; i=e[i].next) {
to = e[i].to;
if (to==fa) continue;
sta[++top]=to;
for (int j=1; j<=v; ++j) {
ans = max(ans, f[u][j]+g[to][v-j]);
f[u][j]=max(f[u][j], max(f[to][j], f[to][j-1]+sum[u]-p[to]));
g[u][j]=max(g[u][j], max(g[to][j], g[to][j-1]+sum[u]-p[fa]));
}
}
ans = max(ans, max(f[u][v], g[u][v]));
for (int i=1; i<=v; ++i) f[u][i]=sum[u], g[u][i]=sum[u]-p[fa];
while (top) {
to=sta[top--];
for (int j=1; j<=v; ++j) {
ans = max(ans, f[u][j]+g[to][v-j]);
f[u][j]=max(f[u][j], max(f[to][j], f[to][j-1]+sum[u]-p[to]));
g[u][j]=max(g[u][j], max(g[to][j], g[to][j-1]+sum[u]-p[fa]));
}
}
ans = max(ans, max(f[u][v], g[u][v]));
}
signed main()
{
n=read(); v=read();
for (int i=1; i<=n; ++i) p[i]=read();
for (int i=1,u,v; i<n; ++i) {u=read(); v=read(); add(u, v); add(v, u);}
dfs(1, 0);
printf("%lld\n", ans);
return 0;
}
题解 park/chase的更多相关文章
- [考试反思]1007csp-s模拟测试63:朦胧
别找了原来没有写过叫<朦胧>的我check过了.(慌的一匹) 总算是比较早的改完了一套题. 但是考的是个啥啊... 前两道题都很卡常导致我想到了正解但是都放弃了. 2e8的复杂度怎么可能能 ...
- 题解报告:hdu 4607 Park Visit(最长链)
Problem Description Claire and her little friend, ykwd, are travelling in Shevchenko's Park! The par ...
- 洛谷 AT2434 JOI 公園 (JOI Park) 题解
人生第一次AC黑题,我太感动了. 每日一题 day31 打卡 Analysis 先跑遍DJ,求出1到 i的最短路.得到每个点到 1号点的距离后,从小到大排序一遍,这时便可以枚举每个点到 1号点的距离修 ...
- Codeforces Round #292 (Div. 1) C. Drazil and Park 线段树
C. Drazil and Park 题目连接: http://codeforces.com/contest/516/problem/C Description Drazil is a monkey. ...
- UVALive 4221 Walk in the Park 扫描线
Walk in the Park 题目连接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemi ...
- Codeforces Round #321 (Div. 2) C. Kefa and Park dfs
C. Kefa and Park Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/580/probl ...
- chd校内选拔赛题目+题解
题目链接 A. Currency System in Geraldion 有1时,所有大于等于1的数都可由1组成.没有1时,最小不幸的数就是1. #include<iostream> ...
- 【CF679D】Bear and Chase 最短路+乱搞
[CF679D]Bear and Chase 题意:近日,鼠国的头号通缉犯,神出鬼没的怪盗——Joker正于摩登市出没!对于名侦探Jack来说,这正是将其捉拿归案的大号时机.形式化地,摩登市可以看成一 ...
- UVALive 6889 City Park 并查集
City Park 题目连接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=122283#problem/F Description P ...
随机推荐
- 20道Java实习生笔试面试选择题(内附答案解析)
1.以下对继承的描述错误的是(A) A.Java中的继承允许一个子类继承多个父类 B.父类更具有通用性,子类更具体 C.Java中的继承存在的传递性 D.当实例化子类时会递归调用父类中的构造方法 解 ...
- 关闭火狐浏览器中的Pocket功能
在火狐(Firefox)浏览器中,默认右键菜单和菜单栏都会有 Pocket按钮 .但是大部分国内用户都不会使用Pocket服务,看着还十分碍眼. 在工具栏的图标还可以通过定制工具栏修改,但是右键菜单中 ...
- 前端-js基础
HTML三把利剑之一,浏览器具有解析js的能力 一.js基础 在HTML中可以将JavaScript/JS的代码写在head中,被script标签所包裹,当浏览器解释HTML时,遇到style标签时, ...
- 深度解析 Lucene 轻量级全文索引实现原理
一.Lucene简介 1.1 Lucene是什么? Lucene是Apache基金会jakarta项目组的一个子项目: Lucene是一个开放源码的全文检索引擎工具包,提供了完整的查询引擎和索引引擎, ...
- PYTHON 解决ModuleNotFoundError: No module named 'win32com'
d:\python37\scripts\>pip install pypiwin32
- Bat脚本备份sqlserver 表结构、存储过程、函数、指定表数据
Bat脚本备份sqlserver 表结构.存储过程.指定表数据: @echo off cd /d %~dp0 ::备份表结构.存储过程和部分配置表的数据 set LogFile=report.log ...
- lucene 类介绍
lucene中重要的类: IndexWriter:lucene中最重要的类之一,主要用于索引的创建 Analyzer(抽象类):分析器,主要用于分析文本,常用的有StandardAnalyzer分析器 ...
- tcpdump软件使用
tcpdump是一个抓包工具, -w 选项是把抓到的包写到二进制文件中,一般扩展名是.cap或.dmp,但tcpdump程序创建文件时并不添加扩展名,可自己指定. -i 是指定要抓包的interfac ...
- 超详细!搭建本地大数据研发环境(16G内存+CDH)
工欲善其事必先利其器,在经过大量的理论学习以后,需要有一个本地的研发环境来进行练手.已经工作的可以不依赖于公司的环境,在家也可以随意的练习.而自学大数据的同学,也可以进行本地练习,大数据是一门偏实践的 ...
- informix错误代码小结
informix错误代码小结 所有错误可以用finderr+错误代码查到,英文的,这里中文注释便于理解. -100 错误的描述:C-ISAM错误:向具有唯一索引的字段加入一个重复值. 系统的操作:该 ...