写在前面

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模拟赛解题报告的更多相关文章

  1. 10.30 NFLS-NOIP模拟赛 解题报告

    总结:今天去了NOIP模拟赛,其实是几道USACO的经典的题目,第一题和最后一题都有思路,第二题是我一开始写了个spfa,写了一半中途发现应该是矩阵乘法,然后没做完,然后就没有然后了!第二题的暴力都没 ...

  2. 2018.10.26NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 + 70\) 实际得分:\(40 + 100 + 70\) 妈妈我又挂分了qwq..T1过了大样例就没管,直到临考试结束前\(10min\)才发现大样例是假 ...

  3. 2018.10.17NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 +100\) 实际得分:\(100 + 100 + 60\) 辣鸡模拟赛.. 5min切掉T1,看了一下T2 T3,感觉T3会被艹爆因为太原了.. 淦了20 ...

  4. 2018.10.16 NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 + 20 = 220\) 实际得分:\(100 + 100 + 30 = 230\) 辣鸡模拟赛.. T1T2都是一眼题,T3考验卡常数还只有一档暴力分. ...

  5. 11.1NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 + 50\) 实际得分:\(100 + 100 + 50\) 感觉老师找的题有点水呀. 上来看T1,woc?裸的等比数列求和?然而我不会公式呀..感觉要凉 ...

  6. 20201115gryz模拟赛解题报告

    写在前面 T1:期望100pts,实际0pts(7:50 ~ 8:50 T2:期望0pts,实际0pts(10:00 ~ 10:35 T3:期望20pts,实际40pts( 9:10 ~ 10:00, ...

  7. 20201102gryz模拟赛解题报告

    简述我的苦逼做题经历 考的是NOIP2017day1原题, 开始看到小凯的疑惑时感觉特水,因为这题初中老师讲过, 很nice的秒切 T2发现是个大模拟,虽然字符串不太会用,但起码题意很好理解 边打代码 ...

  8. 20161022 NOIP模拟赛 解题报告

     好元素 [问题描述] 小A一直认为,如果在一个由N个整数组成的数列{An}中,存在以下情况: Am+An+Ap = Ai (1 <= m, n, p < i <= N ,  m,n ...

  9. 【模拟赛】BYVoid魔兽世界模拟赛 解题报告

    题目名称(点击进入相关题解) 血色先锋军 灵魂分流药剂 地铁重组 埃雷萨拉斯寻宝 源文件名(.c/.cpp/.pas) scarlet soultap subway eldrethalas 输入文件名 ...

随机推荐

  1. Linux嵌入式学习-远程过程调用-Binder系统

    Binder系统的C程序使用示例IPC : Inter-Process Communication, 进程间通信RPC : Remote Procedure Call, 远程过程调用 这里我们直接只用 ...

  2. 什么是Redis?

    Remote Dictionary Server(Redis)是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.它通常被 ...

  3. IO输入和输出

    编程语言的I/O类库中常用使用流这个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接受端对象."流"屏蔽了实际的I/O设备中处理数据的细节. JAVA类库中的 ...

  4. C++作用域限定符:private/public与protected

    C++的作用域限定符其实涉及到了C++特性中的封装和继承. public/private:涉及类的封装特性.对于一个类需要对外展示的部分,我们可以将其声明为public,对于不希望对外展示的,我们将其 ...

  5. Azure Service Bus(三)在 .NET Core Web 应用程序发送ServiceBus Queue

    一,引言 在之前上一篇讲解到 Azure ServiceBus Queue 中,我们实地的演示了在控制台中如何操作ServiceBus Queue ,使用 Azure.Messgae.Service ...

  6. js--数组的every()和some()方法检测数组是否满足条件的使用介绍

    前言 阅读本文之前先来思考一个问题,如何如实现判断一个数组中是否存在满足条件的元素,如何去判断数组中是否全部元素都满足判断条件,这里可能能想到使用for循环遍历数组,if()判断每一项是否符合条件,同 ...

  7. MySQL中的这个池子,强的一批!

    Mysql 中数据是要落盘的,这点大家都知道.读写磁盘速度是很慢的,尤其和内存比起来更是没的说.但是,我们平时在执行 SQL 时,无论写操作还是读操作都能很快得到结果,并没有预想中的那么慢. 可能你会 ...

  8. Lesson_strange_words5

    certain 一些 the company's 公司的 implement 实现 plane 平面 sluggishly 迟缓地,缓慢地 frustrated 懊恼的 profiler 分析器,分析 ...

  9. 使用python做一个IRC在线下载器

    使用python做一个IRC在线下载器 1.开发流程 2.软件流程 3.开始 3.0 准备工作 3.1寻找API接口 3.2 文件模块 3.2.1 选择文件弹窗 3.2.2 提取文件名 3.2.2.1 ...

  10. Linux命令整理,用户管理,用户组管理,系统管理,目录管理常用命令

    知识点梳理 Linux课堂笔记 学习目标 能够知道什么是Linux系统以及它的应用场景 能够独立完成安装VMware虚拟机和网络配置 能够独立完成安装CentOS以及远程终端SecureCRT 能够熟 ...