NOIP2018提高组Day1 解题报告
前言
关于\(NOIP2018\),详见此博客:NOIP2018学军中学游记(11.09~11.11)。
这次\(NOIP\ Day1\)的题目听说很简单(毕竟是三道原题),然而我\(T3\)依然悲剧地写炸了。
很奇怪啊,毕竟在几乎所有民间数据中我这题都\(AC\)了... ...
\(T1\):铺设道路(点此看题面)
另一个题面
我的思路是,每个元素肯定都是由其左右两边第一个比它小的数转移而来的。
于是就开了两个单调栈,前后各扫一遍,求出了答案。
然而貌似还有更简单的解法?但我不会。
代码如下:
#include<bits/stdc++.h>
#define N 100000
using namespace std;
int n,a[N+5],s[N+5],Stack[N+5];
int main()
{register int i,ans=0,Top=0;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);for(i=1;i<=n;++i)//从前往后,求出第一个小于等于a[i]的数{while(Top&&Stack[Top]>=a[i]) --Top;//单调栈s[i]=a[i]-Stack[Top],Stack[++Top]=a[i];//将a[i]-Stack[Top]存储下来,然后将a[i]加入栈}for(Top=0,i=n;i;--i)//从后往前,求出第一个小于a[i]的数{while(Top&&Stack[Top]>a[i]) --Top;//单调栈,注意前面加了=,这题就不能加了,否则会重复计算ans+=min(s[i],a[i]-Stack[Top]),Stack[++Top]=a[i];//统计答案}return printf("%d",ans),0;
}
\(T2\):货币系统(点此看题面)
比较裸的完全背包,但是我不会。
我的思路就是先\(sort\)一遍,然后暴力更新每种价值是否能由之前的价值组合而成。
这样显然会\(TLE\)。
于是我又考虑再用一个\(lst\)数组存储每种价值上一次是被价值为多少的元素更新的,如果上次就是由当前元素更新的,则可直接\(break\)。
这样一优化就\(AC\)了(实际上加上这个优化之后与完全背包应该是等价的)。
代码如下:
#include<bits/stdc++.h>
#define N 100
#define P 25000
using namespace std;
inline void Gmax(int &x,int y) {x<y&&(x=y);}
int n,a[N+5],vis[P+5],lst[P+5];
int main()
{register int T,i,j,k,ans,Max;for(scanf("%d",&T);T;--T){for(scanf("%d",&n),ans=n,Max=0,i=1;i<=n;++i) scanf("%d",&a[i]),Gmax(Max,a[i]);//求最大值for(vis[0]=T,sort(a+1,a+n+1),i=1;i<=n;++i)//现将a[i]排序一遍,并标记价值0已被访问{if(vis[a[i]]^T)//如果当前的价值不可以被之前的价值组合而成{for(j=Max;~j;--j)//枚举值 {if(vis[j]^T) continue;//如果当前值不能被之前的价值组合而成,跳过for(k=1;1LL*a[i]*k+j<=Max;++k)//更新{if(vis[a[i]*k+j]^T||lst[a[i]*k+j]^a[i]) vis[a[i]*k+j]=T,lst[a[i]*k+j]=a[i];//如果没访问过,或不是由当前价值的元素更新的,更新其vis数组和lst数组else break;//否则,可以直接退出循环}}}else --ans;//如果可以组合而成,将ans减1}printf("%d\n",ans);}
}
\(T3\):赛道修建(点此看题面)
这题有很多做法,我个人认为还是二分+\(multiset\)比较好写。
首先,先二分答案\(ans\)。(关于二分的上界,可以设置为树的直径)
关于如何验证,我们可以考虑用一个变量\(tot\)存储满足条件的路径数,并对树上每一个节点开一个\(multiset\)。
对于当前节点\(x\),设其有\(Size\)个子节点,由于每条边只能选择一次,则最多只有\(Size\)条从子节点到其的路径会被选择。
而这些路径可能有长度大于等于\(ans\)的,对于这样的边,直接将\(tot\)加\(1\)即可,否则,可以将其扔入\(multiset\)。
比较显然,我们可以开一个变量\(res\)来存储没有被选择的边中最长边的长度。然后从小到大枚举剩下的路径,每次找到与其和大于等于\(ans\)的最短边,并将它们同时删除,然后将\(tot\)加\(1\)。如果找不到,就更新\(res\)。
最后返回\(res\),就是最后选择的通向父节点的路径。
代码如下:
#include<bits/stdc++.h>
#define Gmax(x,y) (x<(y)&&(x=(y)))
#define Gmin(x,y) (x>(y)&&(x=(y)))
#define N 50000
#define add(x,y,v) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].val=v)
using namespace std;
int n,m,ee,lnk[N+5];
struct edge
{int to,nxt,val,used;
}e[(N<<1)+5];
class Class_FIO
{private:#define Fsize 100000#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)#define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];public:Class_FIO() {A=B=Fin;}inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}inline void write(int x) {if(!x) return pc('0');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
}F;
class Class_TreeDiameterSolver//求树的直径,实际上可以直接用BFS,但我用了树形DP
{private:int ans,Max[N+5],Max_[N+5],MaxSon[N+5];inline void dfs1(int x,int lst){register int i;for(Max[x]=Max_[x]=MaxSon[x]=0,i=lnk[x];i;i=e[i].nxt){if(!(e[i].to^lst)) continue;dfs1(e[i].to,x);if(Max[e[i].to]+e[i].val>Max[x]) Max_[x]=Max[x],Max[x]=Max[MaxSon[x]=e[i].to]+e[i].val;else if(Max[e[i].to]+e[i].val>Max_[x]) Max_[x]=Max[e[i].to]+e[i].val;}Gmax(ans,Max[x]+Max_[x]);}inline void dfs2(int x,int lst,int val){register int i;for(i=lnk[x];i;i=e[i].nxt){if(!(e[i].to^lst)) continue;dfs2(e[i].to,x,max(val,e[i].to^MaxSon[x]?Max[x]:Max_[x])+e[i].val);}Gmax(ans,Max[x]+val);}public:inline int GetAns() {return dfs1(1,0),dfs2(1,0,0),ans;}
}TD;
class Class_Checker//验证答案
{private:int tot;multiset<int> s[N+5];multiset<int>::iterator p;inline int dfs(int x,int lst,int val)//遍历树,x表示当前访问到的节点,lst表示父节点,val表示当前验证的答案{register int i,t,res=0;//res存储没有被选择边中最长边的长度for(s[x].clear(),i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&((t=dfs(e[i].to,x,val)+e[i].val)>=val?++tot:(s[x].insert(t),0));//枚举子节点,如果当前边长度大于等于val,则将tot加1,否则将其扔入multisetwhile(!s[x].empty())//如果multiset不为空{if(t=*s[x].begin(),!(s[x].size()^1)) return max(res,t);//如果只剩一条边,返回res与当前边长度的较大值(p=s[x].lower_bound(val-t))==s[x].begin()&&!(s[x].count(t)^1)&&(++p,0),(p==s[x].end()?Gmax(res,t):(s[x].erase(p),++tot)),s[x].erase(s[x].begin());//找到与其和大于等于ans的最短边,并将它们同时删除,然后将tot加1。如果找不到,就更新res}return res;//返回res}public:inline bool Check(int val) {return tot=0,dfs(1,0,val),tot>=m;}//判断tot是否大于等于m
}C;
int main()
{register int i,x,y,v,l,r,mid;for(F.read(n),F.read(m),i=1;i<n;++i) F.read(x),F.read(y),F.read(v),add(x,y,v),add(y,x,v);for(mid=(l=0)+(r=TD.GetAns())+1>>1;l<r;mid=l+r+1>>1) C.Check(mid)?l=mid:r=mid-1;//二分答案return F.write(l),F.clear(),0;
}
转载于:https://www.cnblogs.com/chenxiaoran666/p/NOIP2018Day1.html
NOIP2018提高组Day1 解题报告相关推荐
- NOIP2013 提高组复赛解题报告
NOIP2013 提高组复赛 day1 day\;1 1002. 火柴排队 贪心+数据结构/归并排序 这个"相邻交换"让我联想到了NOIP2012_day1_task2_game那 ...
- NOIP2016提高组复赛解题报告
Day1 T1-玩具谜题 Day1 T2-天天爱跑步 Day1 T3-换教室 Day2 T1-组合数问题 Day2 T2-蚯蚓 Day2 T3-愤怒的小鸟 转载于:https://www.cnblog ...
- NOIP2018提高组比赛总结
NOIP2018提高组比赛总结 前言 新赛季,依旧有很多失误. 在些许的遗憾和无奈中,NOIP2018,撒花结束 纵观今年的整一场NOIP,有许多值得总结的地方 正文 NOIP2018初赛 第二次参加 ...
- NOIP2018提高组心路历程(AFO+自闭)
NOIP2018提高组历程(AFO+自闭) 在不断地考试考试考试(浪浪浪)中,不知不觉,11月9号这个出征日就到来了,再出发前还是有很多小插曲的(比如刚好正面遇到她,吃好饭后还对视了一眼).随着大巴的 ...
- P5049 [NOIP2018 提高组] 旅行
P5049 [NOIP2018 提高组] 旅行 题意: 一棵树(可能是基环树),从1出发,每到达一个新的点就记录下编号.求一种走法使得记录下来的编号字典序最小. 1≤n≤500000 m=n−1 或 ...
- 51Nod NOIP2018提高组省一冲奖班模测训练
51Nod NOIP2018提高组省一冲奖班模测训练 NOIP2018提高组省一冲奖班模测训练1 T1 珂朵莉的旅行 T2 奈芙莲的序列 T3 奈芙莲的护符 NOIP2018提高组省一冲奖班模测训练2 ...
- 学大伟业Day1解题报告
学大伟业Day1解题报告 张炳琪 一. 时间分配 T1:30分钟 T2: 60分钟 T3:100分钟 二.答题情况及错因 T1:100 T2:55 T3 ...
- NOIP2018提高组省一冲奖班模测训练(三)
NOIP2018提高组省一冲奖班模测训练(三) 自己按照noip的方式考,只在最后一两分钟交了一次 第一题过了,对拍拍到尾. 第二题不会.考试时往组合计数的方向想,推公式,推了一个多小时,大脑爆炸,还 ...
- NOIP2018提高组省一冲奖班模测训练2 T3 XYK的音游
10月22日NOIP2018提高组省一冲奖班模测训练2 T3 XYK的音游 题目描述 XYK最近入坑了一个新音游. 游戏界面上有Ñ个并排的按键,当前这首歌有米个鼓点.游戏的玩法是在鼓点的时刻移动鼠标到 ...
最新文章
- npm i和npm install的区别
- LoadRunner 技巧之 手动关联与预关联
- matlab中rand函数使用
- R语言基于线性回归(Linear Regression)进行特征筛选(feature selection)
- 软件测试2019:第七次作业—— 用户体验测试
- 公积金联名卡——提取公积金用,用身份证即可办理
- golang中的可见性
- javascript标签在页面中的位置探讨
- Kettle能做什么?
- ssl1500-最短路上的统计【Floyd】
- Java小白进阶笔记(3)-初级面向对象
- Nginx 负载均衡策略之加权轮询分析
- mysql5.7.11源码安装,mysql 5.7.11 源码安装
- Java 核心内容相关面试题【2】
- 英文语音识别_英文语音识别软件_英文语音识别翻译 - 云+社区 - 腾讯云
- Windows添加启动项的两种方法
- HDOJ--1864--最大报销额
- 点石成金 访客至上的Web和移动可用性设计秘笈pdf
- 本科毕业论文查重网站分享(维普、知网、万方、大雅等)
- python基础(16):学生信息管理系统——Python编写(附全部代码)