7.15考试总结(NOIP模拟16)[Star Way To Heaven·God Knows·Lost My Music]
败者死于绝望,胜者死于渴望。
前言
一看这个题就来者不善,对于第一题第一眼以为是一个大模拟,没想到是最小生成树。
对于第二题,先是看到了状压可以搞到的 20pts 然后对着暴力一顿猛调后来发现是题面理解错了。
最后 40min 的时候还是把目光投向了这个题的另一个部分分,然后搞了一个区间 DP 但是应该是 线性 DP。
然后我就又凉了,第三题第一眼是输,第二眼是 DFS 序,第三眼是 DFS 序上的线段树,再然后就老老实实去整暴力了。
后来题目名字在网上一搜,竟然都是歌名。。
T1 Star Way To Heaven
解题思路
正解是最小生成树,把上下边界当作两个点来看,然后就搞各个点之间的距离再用 Prim 求最小生成树了。
注意一点,这里用 Kruskal会 TLE 因为多了一个 \(logn\) 的复杂度。
下面主要证明一下最小生成树解法的正确性。
比如下面的这个图

所有最小边权的边所连接的就好似连接了上下两个边界的一个阻断线,显然,我们是一定要从其中穿过去的。
那么,我们一定要选择其中权值最大的边的中点穿过。
因此,答案就是最小生成树上最大边权的一半
code
#include<bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=6e3+10,INF=1e18;
int n,m,tot;
bool vis[N];
double ans,dis[N];
struct Node
{
int x,y;
}s[N];
double dist(double x,double y,double x2,double y2)
{
return sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2));
}
signed main()
{
n=read();
m=read();
tot=read();
for(int i=1;i<=tot;i++)
{
s[i].x=read();
s[i].y=read();
dis[i]=s[i].y;
}
dis[tot+1]=m;
for(int i=1;i<=tot+1;i++)
{
int pos=0;
for(int j=1;j<=tot+1;j++)
if(!vis[j]&&(!pos||dis[j]<dis[pos]))
pos=j;
vis[pos]=true;
ans=max(ans,dis[pos]);
if(pos==tot+1)
break;
for(int j=1;j<=tot;j++)
if(!vis[j])
dis[j]=min(dis[j],dist(s[pos].x,s[pos].y,s[j].x,s[j].y));
dis[tot+1]=min(dis[tot+1],1.0*m-s[pos].y);
}
printf("%.10lf",ans/2);
return 0;
}
T2 God Knows
解题思路
本题的思路或许有一点难懂,就是那种只可意会不可言传的感觉。
首先要明白一个概念:极长上升序列。(对于之后的点都不可以比这个点大)
再看一下 40pts 的做法,直接暴力 DP 设 \(f_i\) 数组表示以 i 结尾的极长上升序列的价值。
然后,先初始化一下每个序列的开始,需要满足之前所有的点的值都小于它。
接下来在枚举结尾点的前提下,一个一个向前跳,要满足从该节点一直到 i-1 节点没有比该节点还要大的点。
其实就是为了防止隔级跳的情况。
在寻找结尾节点的时候和寻找起始节点的相反(保证 i 到 n 没有比它大的点)
然后我们就得到了暴力DP的\(code\)
但是 \(n^2\) 的似乎太慢了,于是我们就可以考虑线段树优化。
好像是类似于一种叫做李超线段树的东西,具体实现细节见代码
code
#include<bits/stdc++.h>
#define int long long
#define ls x<<1
#define rs x<<1|1
#define f() cout<<"Fuck"<<endl;
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=2e5+10,INF=1e18;//v为新的权值
int n,las,v,s[N],val[N],q[N<<2];//q数组记录之前的最有解
struct Segment_Tree
{
int las,dat;//dat就是前面的 f 数组并且必须以这个节点结尾,las表示每个的最后的那个点
}tre[N<<2];//las数组表示当前节点所在的极长序列的末尾
int solve(int x,int l,int r,int pos)
{
if(l==r) return (tre[x].las>pos)?tre[x].dat:INF;
int mid=(l+r)>>1;
if(tre[rs].las<=pos) return solve(ls,l,mid,pos);//不符合直接左儿子
return min(q[x],solve(rs,mid+1,r,pos));//左儿子的部分一定是极长上升序列的部分
}
void push_up(int x,int l,int r)
{
int mid=(l+r)>>1;
tre[x].las=max(tre[ls].las,tre[rs].las);
q[x]=solve(ls,l,mid,tre[rs].las);
}
void insert(int x,int l,int r,int pos,int num,int vall)
{
if(l==r)
{
tre[x].dat=vall;
tre[x].las=num;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) insert(ls,l,mid,pos,num,vall);
else insert(rs,mid+1,r,pos,num,vall);
push_up(x,l,r);
}
void query(int x,int l,int r,int pos)
{
if(r<=pos)
{
v=min(v,solve(x,l,r,las));//只要在这个点之前就查询最小的价值
las=max(las,tre[x].las);
return ;
}
int mid=(l+r)>>1;
if(mid<pos) query(rs,mid+1,r,pos);
query(ls,l,mid,pos);//相当于向前跳的一个过程
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int i=1;i<=n;i++)
val[i]=read();
memset(q,0x7f,sizeof(q));
for(int i=1;i<=n;i++)
{
las=0;
v=INF;
query(1,1,n,s[i]);//求值储存到v并且对于前面的进行更新
if(v>=INF) v=0;
insert(1,1,n,s[i],i,v+val[i]);
}
las=0;
v=INF;
query(1,1,n,n);
printf("%lld",v);
return 0;
}
T3 Lost My Music
解题思路
这个题的第一思路还是在树上维护某些东西,但是能想到的最优的也就只是在每条链上跳了。
但是在链上跳可以获得 50pts 的巨额分数(前提是你不和我一样开小数组)
正解就是什么可持久化栈维护凸包。
But,在我颓了别的题解之后发现这并没有什么用。
直接在树上用倍增维护凸包就非常的棒,嗯,就很棒。
对于下图,显然我们应该维护一个下凸包,对于 D 点的解从 C 点转移比从之前任意一点转移都要更优。
现在举 C 和 B 点转移来对比也就是:\(\dfrac{c_D-c_B}{dep_D-dep_B}\ge \dfrac{c_D-c_C}{dep_D-dep_C}\) 就可以进行更新。
再次基础上优化倍增就好了。

code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=5e5+10,INF=1e18;
int n,s[N],fa[N],dep[N],f[N][25];
int tot,ver[N],head[N],nxt[N];
double ans[N];
inline void add_edge(int x,int y)
{
ver[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
bool judge(int x,int y,int z)
{
return (1.0*s[z]-1.0*s[x])*(1.0*dep[z]-1.0*dep[y])>=(1.0*s[z]-1.0*s[y])*(1.0*dep[z]-1.0*dep[x]);
}
void dfs(int x)
{
dep[x]=dep[fa[x]]+1;
int pos=fa[x];
for(int i=20;i>=0;i--)
{
int temp=f[pos][i];
if(temp<=1) continue;
if(judge(f[temp][0],temp,x))
pos=temp;
}
if(pos!=1&&judge(f[pos][0],pos,x))
pos=f[pos][0];
f[x][0]=pos;
for(int i=0;f[x][i];i++)
f[x][i+1]=f[f[x][i]][i];
for(int i=head[x];i;i=nxt[i])
dfs(ver[i]);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int i=2;i<=n;i++)
{
fa[i]=read();
add_edge(fa[i],i);
}
dfs(1);
for(int i=2;i<=n;i++)
printf("%.10lf\n", (1.0*s[f[i][0]]-1.0*s[i])/(1.0*dep[i]-dep[f[i][0]]) );
return 0;
}
7.15考试总结(NOIP模拟16)[Star Way To Heaven·God Knows·Lost My Music]的更多相关文章
- 2021.7.15考试总结[NOIP模拟16]
ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...
- 2021.8.15考试总结[NOIP模拟40]
T1 送花 线段树.枚举右端点,线段树记录左端点对应的值. 每次对当前颜色上上次出现的位置到上次出现的位置区间减,上次出现的位置到当前位置区间加. $code:$ 1 #include<bits ...
- [考试总结]noip模拟16
达成成就,一天更3篇总结. 又是一个暴力场 别问我为什么开局 \(5\) 分钟就问老师为什么 \(T3\) 没有提交的窗口. 开题读题,一路自闭到 \(T3\) ,发现 \(T3\) 可打暴力,所以一 ...
- 2021.10.15考试总结[NOIP模拟77]
\(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2) 洛谷题单 看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人 然后就急忙去干T2T3了 后来考完一看,只有\(T1\)骗到了\(15pts\)[ ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- Noip模拟16 2021.7.15
题目真是越来越变态了 T1 Star Way To Heaven 首先,你要看出这是一个最小生成树的题(妙吧?) 为什么可以呢? 我们发现从两点连线的中点过是最优的,但是上下边界怎么办呢? 我们把上下 ...
- NOIP模拟16:「Star Way To Heaven·God Knows·Loost My Music」
T1:Star Way To Heaven 基本思路: 最小生成树. 假如我们将上边界与下边界看作一个点,然后从上边界经过星星向下边界连边,会发现,他会形成一条线将整个矩形分为左右两个部分. ...
随机推荐
- Netty 框架学习 —— ByteBuf
概述 网络数据的基本单位总是字节,Java NIO 提供了 ByteBuffer 作为它的字节容器,但这个类的使用过于复杂.Netty 的 ByteBuf 具有卓越的功能性和灵活性,可以作为 Byte ...
- 把HttpClient换成IHttpClientFactory之后,放心多了
前言 关于HttpClient的使用,个人在很多场景都派上用场了,比如在Winform或后台服务中用其调用接口获取和上传数据.微服务中用其进行各服务之间的数据共享等,到目前来看,似乎还没有出现过什么问 ...
- TensorFlow入门实操课程第一章练习笔记
在本练习中,您将尝试构建一个神经网络,让它根据一个简单的公式来预测房屋的价格. 想象一下,如果房子的定价很简单,带一间卧室的房子价格是5万+5万,那么一间卧室的房子要花10万元:两间卧室的房子就要花1 ...
- 解决git冲突
多个开发者同时操作git中的同一个文件,第一个人在commit和push的时候是可以正常提交的,而之后的开发者执行pull,就会报冲突异常conflict. 解决方案: 全部采用当前更改 之后再去gi ...
- SpringBoot项目创建流程--SpringMVC
SpringBoot项目创建步骤 1. 创建SpringBoot工程 (1) File → New → Project → Spring Initilizr (2) Name:MySpringBoot ...
- Go语言判断一个字节的高位大于四
Go语言判断一个字节的高位大于四 1.步骤: 第一步,将该字节的低位清零(与0xF0进行&运算) 为了后面与0x40比较 0xF0转为二进制是1111 0000,&运算(两个同时为1, ...
- qemu-ga windows下的安装及监控开发
windows安装qemu-ga 虚拟机配置里添加virtio serial端口 #virsh edit instance-name devices里添加下面这段配置, 1 <channel t ...
- DDoS攻击的工具介绍
1.低轨道离子加农炮(LOIC) 1.1 什么是低轨道离子加农炮(LOIC)? 低轨道离子加农炮是通常用于发起DoS和DDoS攻击的工具.它最初是由Praetox Technology作为网络压力测试 ...
- Opencv 播放mp4文件和读取摄像头图以及可能会发生的一些异常问题解决方法
学习内容 学习Opencv 读取并播放本地视频和打开摄像头图像以及可能会发生的一些异常问题解决方法 代码演示 电脑环境信息: OpenCV版本:4.5.2 ,vs2017 1.视频文件读取与播放 加载 ...
- 六QT使用mqtt
QT官方的mqtt是qmqtt,头文件是 #include <qmqttclient.h> 官方的文档地址 https://doc.qt.io/QtMQTT/qmqttclient.htm ...