• 考试总结 模拟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
    ",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
    ",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
    ",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
    愿你在迷茫时,记起自己的珍贵。
  • 相关阅读:
    [导入]CodeSmith基础(六)
    [导入]CodeSmith基础(五)
    POJ 2229 Sumsets(经典2次幂和问题)
    UVa 10820 Send a Table(欧拉函数)
    UVa 571 Jugs(经典倒水问题)
    UVa 10717 Mint(LCM)
    UVa 10791 Minimum Sum LCM(素因子分解)
    汇编的艺术(01)sizeof operator
    UVa 11121 Base 2(负数进制)
    UVa 106 Fermat vs. Pythagoras(毕达哥拉斯定理)
  • 原文地址:https://www.cnblogs.com/casun547/p/11369452.html
Copyright © 2020-2023  润新知