前言

关于\(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,否则将其扔入multiset
while(!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;
}

NOIP2018提高组Day1 解题报告的更多相关文章

  1. NOIP2018提高组Day2 解题报告

    前言 关于\(NOIP2018\),详见此博客:NOIP2018学军中学游记(11.09~11.11). \(Day2\)的题目和\(Day1\)比起来,真的是难了很多啊. \(T1\):旅行(点此看 ...

  2. 【NOIP2015】提高组D1 解题报告

    P1978神奇的幻方 Accepted 描述 幻方是一种很神奇的 N ∗ N 矩阵:它由数字 1,2,3, … … , N ∗ N 构成,且每行.每列及两条对角线上的数字之和都相同. 当 N 为奇数时 ...

  3. 【未完成0.0】Noip2012提高组day2 解题报告

    第一次写一套题的解题报告,感觉会比较长.(更新中Loading....):) 题目: 第一题:同余方程 描述 求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解. 格式 输入格式 输入只有一 ...

  4. NOIP2018普及组初赛解题报告

    本蒟蒻参加了今年的NOIP2018普及组的初赛 感觉要凉 总而言之,今年的题要说完全没有难度倒也不至于,还有不少拼RP的题,比如第一次问题求解考逻辑推理,第一次完善程序考双链表等 下面我就和大家一起看 ...

  5. noip2015提高组day2解题报告

    1.跳石头 题目描述 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石( ...

  6. NOIP 2018 提高组初赛解题报告

    单项选择题: D 进制转换题,送分: D 计算机常识题,Python是解释运行的: B 常识题,1984年小平爷爷曰:“娃娃抓起”: A 数据结构常识题,带进去两个数据就可以选出来: D 历年真题没有 ...

  7. HGOI20180812 (NOIP2018 提高组 Day1 模拟试题)

    前缀数组其实就是有序的,那么答案显然是      我们尝试求出通项公式: 证明如下: 因为 所以: 解之得: 更加通俗的写法如下: 易知  令 那么, (错位相减) 由易知等式代入得, 所以, 所以程 ...

  8. 牛客NOIP暑期七天营-提高组1 解题报告

    https://ac.nowcoder.com/acm/contest/920#question A 构造+双指针 发现m的限制是1e5,而点数是5e4,所以不能构造太多的边,思考一下最短路树的定义. ...

  9. 洛谷 P5019 铺设道路 & [NOIP2018提高组](贪心)

    题目链接 https://www.luogu.org/problem/P5019 解题思路 一道典型的贪心题. 假设从左往右填坑,如果第i个深与第i+1个,那么第i+1个就不需要额外填: 如果第i+1 ...

随机推荐

  1. 猜拳游戏三局两胜------java实现代码

    package com.javasm.exerices02; import java.util.ArrayList; import java.util.List; import java.util.R ...

  2. Repeater+AspNetPager+Ajax留言板

    最近想要巩固下基础知识,于是写了一个比较简单易懂实用的留言板. 部分样式参考了CSDN(貌似最近一直很火),部分源码参照了Alexis. 主要结构: 1.前期准备 2.Repeater+AspNetP ...

  3. CentOS 6.6 x64安装TensorFlow

    CentOS 6.6 x64安装TensorFlow升级Python到2.7(系统自带Python版本为2.6) // 安装编译工具 $ yum -y install gcc automake aut ...

  4. Exadata X2-2 更换 存储节点Flash卡电池(ESM)

    Exadata X2-2中的F20 Flash卡含有电源存储模块ESM(Energy Storage Module ), 也就是我们常说的电池,当主机异常断电时,ESM给Flash模块提供备用电源.实 ...

  5. 如何顺畅使用sourcetree可视化工具

    http://www.360doc.com/content/17/0711/10/11253639_670493403.shtml sourcetree软件下载 下载地址:https://www.so ...

  6. windows下apache服务器的下载,安装,配置

    1.进行apache官网->Download->Files for Microsoft Windows->ApacheHaus,然后选择合适的版本下载 2.将下载下来的压缩包解压到合 ...

  7. JVM垃圾收集器总结

    前言: 了解了JVM垃圾回收算法之后就要说说垃圾收集器了. 一.三个概念 Stop-the-World:JVM执行任何一种GC算法时是会停止应用程序的执行的,所以大多数GC优化都是从减少Stop-th ...

  8. ADODB.Stream在进行文件上传时报错

    最近在做web项目,有个控件是上传材料文件和文件夹,本地运行正常,放到服务器上,一直报错:AutoRuntime服务器无法创建..... 解决方法: 1.配置ie浏览器的安全级别 2.修改ie浏览器对 ...

  9. 使用Foxfly.Net读取STEP文件

    Foxfly.Net是具备基本的几何建模和CAD文件读取功能.本文主要介绍读取STP/STEP文件的使用方法. 1.初始化 项目中引入FoxflyNet.dll程序集,在Program.cs中初始化建 ...

  10. VS2017无法进入断点调试且移动到breakpoint上的时候报错“breakpoint will not currently be hit. the source code is different from original version. ”

    我尝试了网上的很多其他办法也翻阅了很多外网资源,这些方法并不能解决我的问题 当然我非常震惊正当我尝试着在stack overflow上发表评论交流一下究竟如何解决的时候,却发现有方法灵验了 ,但是每个 ...