题目真是越来越变态了

T1 Star Way To Heaven

首先,你要看出这是一个最小生成树的题(妙吧?)

为什么可以呢?

我们发现从两点连线的中点过是最优的,但是上下边界怎么办呢?

我们把上下边界看作两个点,每个点和它都连边,这样就可以跑最小生成树了

然而不能用kruskar,多一个$log$就会炸列

只能选用$prim$算法$n^2$已经是最优秀的了

找到生成树里面最大的边/2即可

 1 #include<bits/stdc++.h>
2 using namespace std;
3 inline int read(){
4 int x=0,f=1; char ch=getchar();
5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
7 return x*f;
8 }
9 const int NN=6005,inf=0x7fffffff;
10 int n,m,k,x[NN],y[NN];
11 double d[NN];
12 inline double dis(double x1,double y1,double x2,double y2){
13 return sqrt(fabs(x2-x1)*fabs(x2-x1)+fabs(y2-y1)*fabs(y2-y1));
14 }
15 namespace WSN{
16 inline int main(){
17 n=read(); m=read(); k=read();
18 double maxn=0;
19 for(int i=1;i<=k;i++){
20 x[i]=read(); y[i]=read();
21 }
22 for(int i=1;i<=k;i++) d[i]=y[i];
23 d[k+1]=m;
24 while(1){
25 double minn=inf; int v;
26 for(int j=1;j<=k+1;j++)
27 if(d[j]<minn && d[j]){
28 minn=d[j];
29 v=j;
30 }
31 maxn=max(maxn,d[v]); d[v]=0;
32 if(v==k+1){
33 printf("%.8lf\n",(double)maxn/2);
34 return 0;
35 }
36 for(int j=1;j<=k;j++){
37 double D=dis(x[j],y[j],x[v],y[v]);
38 if(d[j]>D) d[j]=D;
39 }
40 d[k+1]=min(d[k+1],(double)m-y[v]);
41 }
42 return 0;
43 }
44 }
45 signed main(){return WSN::main();}

T2 God Knows

好吧,这题skyh大佬都写了一堆而且放上了代码。

首先考虑$n^2$的转移柿子,比较像友好城市:

设$dp_i$表示已经处理到的边。

$dp[i]=\min \limits_{j<i,p[j]<p[i],\forall k,j<k<i,p[k]<p[j]或p[k]>p[i]}dp[j]+c[i]$

这样我们可以先处理出可能为起点的点,然后找与其不相交的点进行转移。

 1 #include<bits/stdc++.h>
2 #define lid (id<<1)
3 #define rid (id<<1|1)
4 using namespace std;
5 inline int min(int a,int b){return a<b?a:b;}
6 inline int max(int a,int b){return a>b?a:b;}
7 inline void swap(int &a,int &b){a^=b^=a^=b;}
8 inline int read(){
9 int x=0,f=1; char ch=getchar();
10 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
11 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
12 return x*f;
13 }
14 const int NN=5e5+5,inf=0x7fffffff;
15 int n,p[NN],c[NN],dp[NN];
16 namespace WSN{
17 inline int main(){
18 n=read();
19 memset(dp,0x3f,sizeof(dp));
20 for(int i=1;i<=n;i++) p[i]=read();
21 for(int i=1;i<=n;i++) c[i]=read();
22 int las=inf;
23 for(int i=1;i<=n;i++)
24 if(las>p[i]){
25 las=p[i];
26 dp[i]=c[i];
27 }
28 for(int i=2;i<=n;i++){
29 int las=0;
30 for(int j=i-1;j>=1;j--)
31 if(p[j]<p[i]&& las<p[j]){
32 dp[i]=min(dp[i],dp[j]+c[i]);
33 las=p[j];
34 }
35 }
36 las=0;int ans=inf;
37 for(int i=n;i>=1;i--){
38 if(las<p[i]){
39 las=p[i];
40 ans=min(ans,dp[i]);
41 }
42 }
43 printf("%d\n",ans);
44 return 0;
45 }
46 }
47 signed main(){return WSN::main();}

然后考虑正解,参考skyh大佬的做法

转化题目含义就是求极长上升子序列的最小权值。

需要考虑维护一个单调栈,然而他又需要用线段树进行维护,这样

我们把这题叫做线段树维护单调栈优化dp 确实比较优秀。。

这样我们就可以在$log$的复杂度优化一层循环,总复杂度为$O(nlogn)$

 1 #include<bits/stdc++.h>
2 #define lid (id<<1)
3 #define rid (id<<1|1)
4 using namespace std;
5 inline int min(int a,int b){return a<b?a:b;}
6 inline int max(int a,int b){return a>b?a:b;}
7 inline void swap(int &a,int &b){a^=b^=a^=b;}
8 inline int read(){
9 int x=0,f=1; char ch=getchar();
10 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
11 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
12 return x*f;
13 }
14 const int NN=5e5+5,inf=0x7fffffff;
15 int n,p[NN],c[NN],t;
16 struct SNOWtree{
17 int ll[NN<<2],rr[NN<<2];
18 int down[NN<<2],minn[NN<<2],upmin[NN<<2];//站底元素 站内最小元素 更新后站内最小元素
19 void build(int id,int l,int r){
20 ll[id]=l; rr[id]=r;
21 down[id]=-1; minn[id]=upmin[id]=inf;
22 if(l==r) return;
23 int mid=(l+r)>>1;
24 build(lid,l,mid); build(rid,mid+1,r);
25 }
26 int calc(int id,int it){
27 if(ll[id]==rr[id]) return down[id]>it? minn[id]:inf;
28 if(down[rid]>it) return min(upmin[lid],calc(rid,it));
29 return calc(lid,it);
30 }
31 int query(int id,int l,int r){
32 if(l<=ll[id]&&rr[id]<=r){
33 int ans=calc(id,t);
34 t=max(down[id],t);
35 return ans;
36 }
37 int ans=inf;
38 if(r>=ll[rid]) ans=min(ans,query(rid,l,r));//询问时先找右侧
39 if(l<=rr[lid]) ans=min(ans,query(lid,l,r));
40 return ans;
41 }
42 void insert(int id,int pos,int tail,int val){
43 if(ll[id]==rr[id]){
44 minn[id]=val;
45 down[id]=tail;
46 return;
47 }
48 if(pos<=rr[lid]) insert(lid,pos,tail,val);
49 else insert(rid,pos,tail,val);
50 down[id]=max(down[lid],down[rid]);
51 minn[id]=min(minn[rid],upmin[lid]=calc(lid,down[rid]));
52 }
53 }tr;
54 namespace WSN{
55 inline int main(){
56 // freopen("1.in","r",stdin);
57 n=read();
58 for(int i=1;i<=n;i++) p[i]=read();
59 for(int i=1;i<=n;i++) c[i]=read();
60 ++n; p[n]=n;
61 tr.build(1,0,n);tr.insert(1,0,0,0);//建立原始节点作为起点(0)与终点(n+1),这样不必再找到每种可能的起点
62 for(int i=1;i<=n;i++){
63 t=-1; //每次更新t值,延伸出一条链进行查找
64 int wsn=tr.query(1,0,p[i]-1)+c[i];//更新并查找p[i]之前的信息
65 tr.insert(1,p[i],i,wsn);//对p[i]的信息加入
66 if(i==n) printf("%d\n",wsn);
67 }
68 return 0;
69 }
70 }
71 signed main(){return WSN::main();}

带注释

T3 Lost My Music

比较轻松的打完暴力,预估20,结果50。。

惊喜

正解竟是斜率维护凸包。。。。

先推一个大佬的斜率优化dp笔记

我们看到这个柿子跟题目问的很相似啊。。

不就是取个负数吗

扫它纳,我们用可持久化栈维护一个下凸包,其斜率递增,那么我们就找到需要查的点与已经查到的点连线中斜率最大的即为答案

也就是凸包切线。

我们记录$ant_{i,j}$为i的第$2^j$级祖先,直接倍增找到最优值记录答案就可以了。

原本应该每次找完暴力弹栈再加上回溯所有要用的儿子,然而这种暴力弹栈操作会被菊花图卡掉变成$n^2$

所以应用倍增思想

 1 #include<bits/stdc++.h>
2 using namespace std;
3 inline int read(){
4 int x=0,f=1; char ch=getchar();
5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
7 return x*f;
8 }
9 const int NN=505000;
10 int n,c[NN],fa[NN],dis[NN];
11 int q[NN],ant[NN][22];
12 double ans[NN];
13 struct SNOW{int to,next;};SNOW e[NN]; int head[NN],rp;
14 inline double calc(int x,int y){return (double)(c[x]-c[y])/(dis[y]-dis[x]);}//先是祖先,后是子孙
15 inline void add(int x,int y){e[++rp]=(SNOW){y,head[x]}; head[x]=rp;}
16 inline void dque(int p){
17 int fp=fa[p];
18 for(int i=20;i>=0;i--)
19 if(ant[ant[fp][i]][0] && calc(ant[ant[fp][i]][0],ant[fp][i])<calc(ant[fp][i],p))
20 fp=ant[ant[fp][i]][0];
21 if(ant[fp][0] && calc(ant[fp][0],fp)<calc(fp,p)) fp=ant[fp][0];
22 ant[p][0]=fp; ans[p]=calc(ant[p][0],p);
23 for(int i=1;i<=20;i++) ant[p][i]=ant[ant[p][i-1]][i-1];
24 }
25 namespace WSN{
26 inline int main(){
27 n=read(); q[1]=1;
28 for(int i=1;i<=n;i++) c[i]=read();
29 for(int i=2;i<=n;i++){int f=read();add(f,i); fa[i]=f;}
30 for(int h=1,t=1;h<=t;h++){
31 dis[q[h]]=dis[fa[q[h]]]+1;
32 dque(q[h]);
33 for(int i=head[q[h]];i;i=e[i].next) q[++t]=e[i].to;
34 }
35 for(int i=2;i<=n;i++) printf("%.8lf\n",ans[i]);
36 return 0;
37 }
38 }
39 signed main(){return WSN::main();}

Noip模拟16 2021.7.15的更多相关文章

  1. Noip模拟77 2021.10.15

    T1 最大或 $T1$因为没有开$1ll$右移给炸掉了,调了一年不知道为啥,最后实在不懂了 换成$pow$就过掉了,但是考场上这题耽误了太多时间,后面的题也就没办法好好打了.... 以后一定要注意右移 ...

  2. Noip模拟40 2021.8.15

    T1 送花 按照题解意思说是扫描线题,但我觉得像一个线段树优化$dp$ 主要思想一样,就是暴力枚举右端点,同时维护左端点的最值, 考虑两种情况, 如果左端点在$r$扫到的数$i$上一次出现的位置之前, ...

  3. 2021.7.15考试总结[NOIP模拟16]

    ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...

  4. Noip模拟78 2021.10.16

    这次时间分配还是非常合理的,但可惜的是$T4$没开$\textit{long long}$挂了$20$ 但是$Arbiter$上赏了蒟蒻$20$分,就非常不错~~~ T1 F 直接拿暴力水就可以过,数 ...

  5. Noip模拟54 2021.9.16

    T1 选择 现在发现好多题目都是隐含的状压,不明面给到数据范围里,之凭借一句话 比如这道题就是按照题目里边给的儿子数量不超过$10$做状压,非常邪门 由于数据范围比较小,怎么暴力就怎么来 从叶子节点向 ...

  6. Noip模拟41 2021.8.16

    T1 你相信引力吗 对于区间的大小关系问题,往往使用单调栈来解决 这道题的优弧和劣弧很烦,考虑将其等价的转化 由于所有的合法情况绕过的弧都不会经过最高的冰锥, 又因为环可以任意亲定起点,这样可以直接把 ...

  7. Noip模拟17 2021.7.16

    我愿称这场考试为STL专练 T1 世界线 巧妙使用$bitset$当作vis数组使用,内存不会炸,操作还方便,的确是极好的. 但是这个题如果不开一半的$bitset$是会炸内存的,因为他能开得很大,但 ...

  8. 7.15考试总结(NOIP模拟16)[Star Way To Heaven·God Knows·Lost My Music]

    败者死于绝望,胜者死于渴望. 前言 一看这个题就来者不善,对于第一题第一眼以为是一个大模拟,没想到是最小生成树. 对于第二题,先是看到了状压可以搞到的 20pts 然后对着暴力一顿猛调后来发现是题面理 ...

  9. 2021.10.26考试总结[冲刺NOIP模拟16]

    T1 树上的数 \(DFS\)一遍.结构体存边好像更快? \(code:\) T1 #include<bits/stdc++.h> using namespace std; namespa ...

随机推荐

  1. vue-cli-service build 环境设置

    zhidao zhouzongshuo的那个是使用vue-cli3打包项目,通过配置不同的指令给项目设置不一样的配置. npm run serve时会把process.env.NODE_ENV设置为' ...

  2. Mac上Markdown的使用

    Markdown是什么,且听我快快道来. 20年前,我第一次接触互联网,当时还是用 28.8k的猫拨号. 我从一本<电脑报>附赠的光盘里,找到了 台湾版的"烘培机"(烘 ...

  3. PTA——c++面向对象基础

    1.结构不是面向对象的主要特征 2.每个 C++程序中都必须包含有这样一个函数,该函数的函数名为main 3.C++对C语言作了很多改进,下列描述中()使得C语言发生了质变,从面向过程变成了面向对象. ...

  4. Jmeter系类(31) - JSR223(1) | 控件介绍

    JSR233 介绍 JSR223控件执行JSR223脚本代码用于创建/更新所需的某些变量 JSR223可以使用其内置的变量,有助于精简脚本,提高开发测试的效率 由于JSR223脚本编译方式基本相同,J ...

  5. python刷题第四周

    本周有所收获的题目: 第一题: 第4章-17 水仙花数(20 分) (20 分) 水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身. 例如:153=1×1×1+5×5×5 ...

  6. chrome 的手机调试工具 toggle device toolbar

    chrome 的手机调试工具 toggle device toolbar 是否可以模拟到不同系统,如苹果系统和安卓系统.

  7. ubuntu系统执行生成密匙命令后,home目录下面没有生成.ssh目录

    ubuntu系统配置git ssh时,执行:ssh-keygen -trsa -C "youremail@example.com",home目录下面没有生成.ssh目录. .ssh ...

  8. regexp 正则表达式

    * 给定字符串 str,检查其是否包含连续重复的字母(a-zA-Z),包含返回 true,否则返回 false input: 'rattler' output: true function conta ...

  9. windows2012安装django

    第一步:下载python3.6.8或者到(https://www.python.org/downloads/release/python-368/)官网下载(Windows x86-64 execut ...

  10. 定要过python二级 第三套

    第一模块   基础操作(共三道题) 1. 安装python 包  我在c  盘打开  但是它给我安装到了d盘得  anaconda3 下面  关键是  我在c盘  打开python .exe   创建 ...