考试报告 模拟24

Posted casun547

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了考试报告 模拟24相关的知识,希望对你有一定的参考价值。

T1

改题时遇到的问题:

1.搜索时只有树才可以dfs(int x,int f)

2.注意开long long!!!!

 题解:

思路不难想(可我考场上还是没想出来),问最小距离的最大值,显然是个二分答案,考虑check(两点之间的距离),上边界和下边界分别抽象成一个点,能不能到,就是看路径上有没有完全阻断的路,那么就可以将每个点按照ans/2的半径作圆,如果有交集就将其连边,那么就从上边界开始dfs,若能找到下边界说明不行,剪枝:先将k个点按照横坐标升序排列,建边的时候如果距离>ans就不用建边了

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 #define R register
 8 using namespace std;
 9 inline int read()
10 
11     int x=0;char ch=getchar();
12     while(ch>9||ch<0)ch=getchar();
13     while(ch<=9&&ch>=0)x=(x<<3)+(x<<1)+(ch^48);ch=getchar();
14     return x;
15 
16 const int maxn=6005;
17 const double eps=1e-8;
18 int n,m,k;
19 struct node
20     int v,nxt;
21 e[maxn*maxn];int h[maxn],nu;
22 void add(int x,int y)
23 
24     e[++nu].v=y;
25     e[nu].nxt=h[x];
26     h[x]=nu;
27 
28 struct poin
29     long long x,y;
30 p[maxn];
31 bool cmp(poin a,poin b)return (a.x==b.x)?a.y<b.y:a.x<b.x;
32 inline double cal(int i,int j)return (p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y);
33 int v[maxn];
34 int dfs(int x)
35 
36     if(x==k+1)return 0;
37     v[x]=1;
38     for(int i=h[x];i;i=e[i].nxt)
39     
40         int y=e[i].v;
41         if(v[y])continue;
42         if(!dfs(y))return 0;
43     
44     return 1;
45 
46 inline int valid(double nw)
47 
48     memset(v,0,sizeof v);
49     memset(h,0,sizeof h);
50     nu=0;
51     for(int i=1;i<=k;++i)
52     
53         if(1.0*p[i].y>1.0*m-nw)add(0,i),add(i,0);
54         if(1.0*p[i].y<nw)add(k+1,i),add(i,k+1);
55         for(int j=i+1;j<=k;++j)
56         
57             if(1.0*(p[j].x-p[i].x)>nw)break;
58             if(cal(i,j)<nw*nw)
59                 add(i,j),add(j,i);
60         
61     
62     return dfs(0);
63 
64 int main()
65 
66 //freopen("starway9.in","r",stdin);
67     n=read(),m=read(),k=read();
68     for(R int i=1;i<=k;++i)
69         p[i].x=read(),p[i].y=read();
70     sort(p+1,p+k+1,cmp);
71     double l=0.0,r=1.0*m;
72     while(r-l>1e-8)
73     
74         R double mid=(l+r)/2.0;
75         if(valid(mid))    l=mid;
76         else r=mid-eps;
77     
78     printf("%.9lf\n",l/2.0);
79 
80 /*
81 g++ 1.cpp  -o 1
82 ./1
83 10 5 2
84 1 1
85 2 3
86 
87 */
View Code

正解:最小生成树,将k个点和上下边界都互相连边,从边界开始跑prim, 由于不断加入的是这个点到已经生成的树上权值最小的边,所以这些边不断地取max,找到另一边界后就可以break了,此时已将在原图上建出一条连接两边界的链了,并且都是最小值,那这其中的max就是答案

T3

原式可以看作是斜率的式子,提个负号,那么就是这个点到其祖先中斜率最大的那个,维护一个凸包(就是后面的斜率都比上一个大),这样在处理一个节点时,比较这个节点和栈顶元素,如果不满足大于即不能是凸包,就不断pop,直到并用其更新ans值,注意回溯时要重新放回去,这能拿80,

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 using namespace std;
 6 #define int long long 
 7 inline int read()
 8 
 9     int x=0;char ch=getchar();
10     while(ch>9||ch<0)ch=getchar();
11     while(ch<=9&&ch>=0)x=(x<<3)+(x<<1)+(ch^48);ch=getchar();
12     return x;
13 
14 inline double min(double x,double y)return x<y?x:y;
15 const int maxn=500005;
16 int n,c[maxn],fa[maxn],dep[maxn];
17 int sta[maxn],top=0;
18 double ans[maxn];
19 struct node
20     int v,nxt;
21 e[maxn];int h[maxn],nu;
22 void add(int x,int y)
23 
24     e[++nu].v=y;
25     e[nu].nxt=h[x];
26     h[x]=nu;
27 
28 inline double cal(int i,int j)
29 
30     return 1.0*(double)(c[i]-c[j])/(double)(dep[i]-dep[j]);
31 
32 int num=0;
33 int sta2[maxn],top2;
34 void dfs(int x)
35 
36     int down=top2;
37     while(x!=1&&top>=2&&(cal(x,sta[top])<cal(sta[top],sta[top-1])))
38         sta2[++top2]=sta[top--];
39     ans[x]=-1.0*cal(x,sta[top]);
40     sta[++top]=x;
41     for(int i=h[x];i;i=e[i].nxt)
42     
43         int y=e[i].v;
44         dep[y]=dep[x]+1;
45         dfs(y);
46     
47     --top;
48     while(top2>down)
49         sta[++top]=sta2[top2--];
50     return;
51 
52 signed main()
53 
54     //freopen("data","r",stdin);
55     n=read();
56     for(int i=1;i<=n;++i)c[i]=read();
57     for(int i=2;i<=n;++i)fa[i]=read(),add(fa[i],i);
58     dep[1]=1;
59     dfs(1);
60     for(int i=2;i<=n;++i)
61         printf("%.10lf\n",ans[i]);
62 
63 /*
64 g++ 1.cpp -o 1
65 ./1
66 
67 8
68 31516 11930 18726 12481 79550 63015 64275 7608
69 1 1 2 4 2 4 5
70 */
View Code

 

再用上链表实现的倍增思路

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 using namespace std;
 6 #define int long long 
 7 inline int read()
 8 
 9     int x=0;char ch=getchar();
10     while(ch>9||ch<0)ch=getchar();
11     while(ch<=9&&ch>=0)x=(x<<3)+(x<<1)+(ch^48);ch=getchar();
12     return x;
13 
14 inline double min(double x,double y)return x<y?x:y;
15 const int maxn=500005;
16 int n,c[maxn],dep[maxn],pre[maxn][25],fa[maxn];
17 double ans[maxn];
18 struct node
19     int v,nxt;
20 e[maxn];int h[maxn],nu;
21 void add(int x,int y)
22 
23     e[++nu].v=y;
24     e[nu].nxt=h[x];
25     h[x]=nu;
26 
27 inline double cal(int i,int j)return 1.0*(double)(c[i]-c[j])/(double)(dep[i]-dep[j]);
28 int que[maxn],fro=1,bac=0;
29 void bfs()
30 
31     que[++bac]=1;
32     while(fro<=bac)
33     
34         int x=que[fro++];
35         dep[x]=dep[fa[x]]+1;
36         int y=fa[x];
37         for(int j=20;j>=0;--j)
38             if(pre[pre[y][j]][0]&&cal(pre[y][j],pre[pre[y][j]][0])>cal(x,pre[y][j]))y=pre[y][j];
39         if(pre[y][0]&&cal(y,pre[y][0])>cal(x,y))y=pre[y][0];
40         pre[x][0]=y;
41         ans[x]=-1.0*cal(x,y);
42         for(int j=1;j<=20;++j)
43             pre[x][j]=pre[pre[x][j-1]][j-1];
44         for(int i=h[x];i;i=e[i].nxt)
45             que[++bac]=e[i].v;
46     
47 
48 signed main()
49 
50     //freopen("data","r",stdin);
51     n=read();
52     for(int i=1;i<=n;++i)c[i]=read();
53     for(int i=2;i<=n;++i)fa[i]=read(),add(fa[i],i);
54     bfs();
55     for(int i=2;i<=n;++i)
56         printf("%.10lf\n",ans[i]);
57 
58 /*
59 g++ 1.cpp -o 1
60 ./1
61 
62 8
63 31516 11930 18726 12481 79550 63015 64275 7608
64 1 1 2 4 2 4 5
65 */
View Code

 

以上是关于考试报告 模拟24的主要内容,如果未能解决你的问题,请参考以下文章

$NOIP 2016 Day1$ 模拟考试 题解报告

$NOIP 2018 Day2$ 模拟考试 题解报告

Noip模拟考试6:解题报告

2018-04-26 模拟考试 答题报告

Noip模拟考试八:解题报告

2019/8/27 校内模拟赛 考试报告