20201101gryz模拟赛解题报告
写在前面
2020rp++
停课的第一场模拟赛
拿上一年的上一年的day1来考的,
结果得分期望220pts,实际135pts,rank3,太菜了
考着考着机房灯突然灭了,当时慌的一批
以为断电代码要没了,还好电脑没事
T1铺设道路
这次T1不想上次那么暴力,一开始感觉还挺有思考量
后来发现可以分治做,但我那个板子好像不会打(我对不起Lucky_block)
然后就整了个线段树来维护,并且只需要建树和上传即可,所以还是蛮简单的
合并过程的原理和正解差不多(赛后我才知道差分O(n)就能过)
需要注意的是在上传的时候要先取和再减去左子树右端点和右子树左端点中的最小值


1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 #define lson i << 1
5 #define rson i << 1 | 1
6 using namespace std;
7 const int MAXN = 1e5+5;
8 struct tree{
9 int sum, l, r;
10 }tree[MAXN << 2];
11 int n;
12 int a[MAXN];
13
14 int read(){
15 int s = 0, w = 1;
16 char ch = getchar();
17 while(ch < '0' || ch > '9') {if(ch == '-') w = -1; ch = getchar(); }
18 while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
19 return s * w;
20 }
21
22 void push_up(int i){
23 tree[i].sum = (tree[lson].sum + tree[rson].sum) - ( min(a[tree[lson].r], a[tree[rson].l]) );
24 return ;
25 }
26
27 void build(int i, int l, int r){
28 tree[i].l = l, tree[i].r = r;
29 if(l == r) {
30 tree[i].sum = a[l];
31 return ;
32 }
33 int mid = (l + r) >> 1;
34 build(lson, l, mid), build(rson, mid + 1, r);
35 push_up(i);
36 return ;
37 }
38
39 int main()
40 {
41 freopen("road.in","r",stdin);
42 freopen("road.out","w",stdout);
43
44 n = read();
45 for(int i = 1; i <= n; ++i) a[i] = read();
46
47 build(1, 1, n);
48
49 printf("%d", tree[1].sum);
50
51 return 0;
52 }
T2货币系统
一开始看错了,以为就是个nlogn的暴力枚举,打完才发现
然后开始想正解,正解没想出来
看到部分分的数据比较小
就开始打暴力,三个小数据点都过了,后来下发的大数据点没过
但当时没找到错误就抱着随缘的心态放了过去,期望80pts,实际25pts
正解:(zzg这就是个完全背包板子)新求的集合一定是原集合子集,并且如果原集合中的某个值珂以用两个更小的值凑出来的话(每个值可以用无限次)那么它珂以被删掉
因为一个面值小的钱不可能被大的合成,所以从小到大排序,并从小到大枚举
转移方程:f[j] |= f[j - a[i]];
f[j]用来记录前面的钱能否合成j这个面值的钱,如果减掉a[i]的那个钱能被合成,那么加上此时枚举到的a[i]的这个钱也可以被合成


1 /*
2 Work by: Suzt_ilymics
3 Knowledge: ??
4 Time: O(??)
5 */
6 #include<iostream>
7 #include<cstdio>
8 #include<cstring>
9 #include<algorithm>
10 using namespace std;
11 int T, n;
12 int a[110];
13 bool f[25100];
14
15 int read(){
16 int w = 1, s = 0;
17 char ch = getchar();
18 while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar(); }
19 while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
20 return s * w;
21 }
22
23 int main()
24 {
25 T = read();
26 while(T--){
27 memset(f, 0, sizeof(f));
28 n = read();
29 int cnt = n;
30 for(int i = 1; i <= n; ++i) a[i] = read();
31 sort(a + 1, a + n + 1);
32 f[0] = 1;
33 for(int i = 1; i <= n; ++i){
34 if(f[a[i]]) {cnt--; continue; }
35 for(int j = a[i]; j <= a[n]; ++j){
36 f[j] |= f[j-a[i]];
37 }
38 }
39 printf("%d\n", cnt);
40 }
41 return 0;
42 }
T3赛道修建
想了一会发现自己根本不会,
然后老老实实的骗部分分,
1、m == 1
发现此时就是求多源最长路,然后莽上floyd(我当时并不知道floyd不能求最长路,但赛后想到可以转化成负边来求啊
发现不对,只好先放过
2、ai == 1
画个样例不难发现这是个“菊花图”,当时做法是排个序然后最大值和最小值配对,在从前到后扫一遍求出最小值来
(没错,这个贪心也是错的,当时我sb没看出来,还以为能骗个20分)
3、bi == ai + 1
可以发现这是条链,这很显然的二分板子啊,那这个20分不就到手了
(Q:你不会二分板子也写错了吧? A:没错,我二分又写挂了)
正解:(从题解上爬的加上老吕讲的
看到题意描述第一反应就是先二分那个修建的 m 条赛道中长度最小的赛道的长度 k ,然后 O(n) 或 O(nlogn) 判断。
那么怎么判断呢?
对于每个结点,把所有传上来的值 val 放进一个 multiset ,其实这些值对答案有贡献就两种情况:
- val ≥ k
- val_a + val_b ≥ k
那么第一种情况可以不用放进 multiset,直接答案 +1 就好了。第二种情况就可以对于每一个最小的元素,在 multiset 中找到第一个 ≥ k 的数,将两个数同时删去,最后把剩下最大的值传到那个结点的父亲
有没有可能对于有些情况直接传最大的数会使答案更大?
当然不会。这个数即使很大也只能对答案贡献加 1,在其没传上去的时候可以跟原来结点的值配对,也只能对答案贡献加 1。
miltiset用法(一篇不错的博客)(我没时间整理只能搬网址了)


1 /*
2 Work by: Suzt_ilymics
3 Knowledge: ??
4 Time: O(??)
5 */
6 #include<iostream>
7 #include<cstdio>
8 #include<set>
9 using namespace std;
10 const int MAXN = 5e4+5;
11 struct edge{
12 int to, w, nxt;
13 }e[MAXN << 1];
14 int head[MAXN], num_edge;
15 int n, m, ans, cnt, up;
16 int sum1, sum2;
17
18 multiset<int> s[MAXN];
19 multiset<int>::iterator it;
20 /*c++语言中,multiset是<set>库中一个非常有用的类型,
21 它可以看成一个序列,
22 插入一个数,删除一个数都能够在O(logn)的时间内完成,
23 而且他能时刻保证序列中的数是有序的,
24 而且序列中可以存在重复的数。*/
25 int read(){
26 int w = 1, s = 0;
27 char ch = getchar();
28 while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar(); }
29 while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
30 return s * w;
31 }
32
33 void add(int from, int to, int w){
34 e[++num_edge] = {to, w, head[from]}, head[from] = num_edge;//更为简洁的存边方式
35 // e[++num_edge].to = to;
36 // e[num_edge].w = w;
37 // e[num_edge].nxt = head[from];
38 // head[from] = num_edge;
39 }
40
41 int dfs(int x, int fa, int mid){
42 s[x].clear();//先把数组清空
43 int val;
44 for(int i = head[x]; i; i = e[i].nxt){
45 int v = e[i].to;
46 if(v == fa) continue;
47 val = dfs(v, x, mid) + e[i].w;//以x为根能用的最长链是儿子的最长链加上与儿子相连的那条链
48 if(val >= mid) cnt++;//如果某条链达到mid直接++
49 else {
50 s[x].insert(val);//否则暂时插入s[x]序列中
51 }
52 }
53 int Max = 0;
54 while(!s[x].empty()){//如果序列不为空(即还有链没用到
55 if(s[x].size() == 1) {
56 return max(Max, *s[x].begin());//如果只有一个元素直接返回Max
57 }
58 it = s[x].lower_bound(mid - *s[x].begin());//找到一个能与s[x]的第一个元素相加超过mid的元素(这个元素是刚刚使条件成立,保证不浪费
59 if(it == s[x].begin() && s[x].count(*it) == 1) it++;//如果这两个数相同并且it的数量等于1,就使it的指向下一个元素
60 if(it == s[x].end()){//如果没有这个元素
61 Max = max(Max, *s[x].begin());//最大值返回第一个值
62 s[x].erase(s[x].find(*s[x].begin()));//清除第一个值 (即这个数暂时不可用
63 }
64 else {
65 cnt++;//如果能用,就意味着配对成一条链
66 s[x].erase(s[x].find(*it));//清除两个元素
67 s[x].erase(s[x].find(*s[x].begin()));
68 }
69 }
70 return Max;//返回能用的最大值
71 }
72
73 int check(int mid){
74 cnt = 0;
75 dfs(1, 0, mid);
76 return cnt >= m;//如果以mid为界能分的链大于等于m,返回1,向上二分,反之返回0,向下二分
77 }
78
79 int dfs1(int x, int fa){//
80 int sum1 = 0, sum2 = 0;//sum1存以x为根节点的最长链,sum2存以x为根节点的次长链
81 for(int i = head[x]; i; i = e[i].nxt){
82 int v = e[i].to;
83 if(v == fa) continue;
84 sum2 = max(sum2, dfs1(v, x) + e[i].w); //最长链的长度 = 每个子节点中的最长链加上它到自己儿子的这条边
85 if(sum1 < sum2) swap(sum1, sum2);//判断以x为根节点的次长链能否成为最长链
86 }
87 up = max(up, sum1 + sum2);
88 return sum1;
89 }
90
91 int main()
92 {
93 n = read(), m = read();
94 for(int i = 1, u, v, w; i < n; ++i){
95 u = read(), v = read(), w = read();
96 add(u, v, w), add(v, u, w);//存边
97 }
98 dfs1(1, 0);
99 int l = 1, r = up;//up表示树上最长链(答案上界
100 while(l <= r){//二分答案
101 int mid = (l + r) >> 1;
102 if(check(mid)) {
103 ans = mid, l = mid + 1;
104 }
105 else r = mid - 1;
106 }
107 printf("%d\n", ans);
108 return 0;
109 }
总结
1、T3还是不怎么懂,以后有时间要再看看
2、我代码能力还是太弱了,一个暴力一个贪心一个二分都写挂了
3、这么久我还是一个dp小白
20201101gryz模拟赛解题报告的更多相关文章
- 10.30 NFLS-NOIP模拟赛 解题报告
总结:今天去了NOIP模拟赛,其实是几道USACO的经典的题目,第一题和最后一题都有思路,第二题是我一开始写了个spfa,写了一半中途发现应该是矩阵乘法,然后没做完,然后就没有然后了!第二题的暴力都没 ...
- 2018.10.26NOIP模拟赛解题报告
心路历程 预计得分:\(100 + 100 + 70\) 实际得分:\(40 + 100 + 70\) 妈妈我又挂分了qwq..T1过了大样例就没管,直到临考试结束前\(10min\)才发现大样例是假 ...
- 2018.10.17NOIP模拟赛解题报告
心路历程 预计得分:\(100 + 100 +100\) 实际得分:\(100 + 100 + 60\) 辣鸡模拟赛.. 5min切掉T1,看了一下T2 T3,感觉T3会被艹爆因为太原了.. 淦了20 ...
- 2018.10.16 NOIP模拟赛解题报告
心路历程 预计得分:\(100 + 100 + 20 = 220\) 实际得分:\(100 + 100 + 30 = 230\) 辣鸡模拟赛.. T1T2都是一眼题,T3考验卡常数还只有一档暴力分. ...
- 11.1NOIP模拟赛解题报告
心路历程 预计得分:\(100 + 100 + 50\) 实际得分:\(100 + 100 + 50\) 感觉老师找的题有点水呀. 上来看T1,woc?裸的等比数列求和?然而我不会公式呀..感觉要凉 ...
- 20201115gryz模拟赛解题报告
写在前面 T1:期望100pts,实际0pts(7:50 ~ 8:50 T2:期望0pts,实际0pts(10:00 ~ 10:35 T3:期望20pts,实际40pts( 9:10 ~ 10:00, ...
- 20201102gryz模拟赛解题报告
简述我的苦逼做题经历 考的是NOIP2017day1原题, 开始看到小凯的疑惑时感觉特水,因为这题初中老师讲过, 很nice的秒切 T2发现是个大模拟,虽然字符串不太会用,但起码题意很好理解 边打代码 ...
- 20161022 NOIP模拟赛 解题报告
好元素 [问题描述] 小A一直认为,如果在一个由N个整数组成的数列{An}中,存在以下情况: Am+An+Ap = Ai (1 <= m, n, p < i <= N , m,n ...
- 【模拟赛】BYVoid魔兽世界模拟赛 解题报告
题目名称(点击进入相关题解) 血色先锋军 灵魂分流药剂 地铁重组 埃雷萨拉斯寻宝 源文件名(.c/.cpp/.pas) scarlet soultap subway eldrethalas 输入文件名 ...
随机推荐
- 配置文件中配置集合类(Map、list)@Value注入map、List
spel表达式就是spring表达式.在java代码中,还有这种写法: @Value("#{'${auth.filter.exclude-urls}'.split(',')}") ...
- [leetcode]49. Group Anagrams重排列字符串分组
是之前的重排列字符串的延伸,判断是重排列后存到HashMap中进行分组 这种HashMap进行分组的方式很常用 public List<List<String>> groupA ...
- JavaScript获取页面元素方法
- 冒泡排序算法JAVA实现版
/***关于冒泡排序,从性能最低版本实现到性能最优版本实现*/public class BubbleSortDemo { public static void sort(int array[]) { ...
- 自动化运维工具-Ansible之2-ad-hoc
自动化运维工具-Ansible之2-ad-hoc 目录 自动化运维工具-Ansible之2-ad-hoc Ansible ad-hoc Ansible命令模块 Ansible软件管理模块 Ansibl ...
- VS2017+qt5.9的安装
VS2017+qt5.9的安装 运行环境: win7旗舰版+vs2017专业版+qt5.9.2 第一步:安装qt5.9.2 下载qt安装包:下载地址http://mirrors.ustc.edu.cn ...
- kafka-spark偏移量提交至redis kafka1.0版本
kafka版本 1.0.0 spark版本 spark-streaming-kafka-0-10_2.11/** * @created by imp ON 2019/12/21 */class Kaf ...
- java的多线程:线程基础
1.线程与进程区别 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行.也可以把它理解为代码运行的上下文.所以线程基本上是 ...
- Linux下docker中安装宝塔面板教程
本人云服务器,装的cent os7.6,在cent os7.6已装了docker,没装的可以借鉴 https://www.cnblogs.com/xiaoyige/p/12673076.html 1. ...
- Scaled-YOLOv4 快速开始,训练自定义数据集
代码: https://github.com/ikuokuo/start-scaled-yolov4 Scaled-YOLOv4 代码: https://github.com/WongKinYiu/S ...