zoukankan      html  css  js  c++  java
  • 0817NOIP模拟测试赛后总结

    吐槽一句:话说NOIP都取消了还叫NOIP模拟真的好么

    于是乎我再次爆炸……(0+20+50=70 rank26)


    赛时状态

    赛时的状态依旧不佳。不过还是硬逼着自己把三道题都读完,然后开始对出题人静坐示威。

    突然意识到这是昨天那套题的day2。后悔昨天没机灵点颓一下。好吧也颓不到。毕竟昨天那套题的题解网上都找不到。

    偷瞥了一眼机房其他人的状态,似乎都非常头疼的样子。一向嘈杂的机房甚至没有几声敲键盘键盘声。

    嗯,我放心了。

    继续抱头想T1,看着double的数据突然想到了二分答案。/滑稽

    然后就没有然后了。想了一个多小时无果,决定弃坑。

    码了一个T2的20分暴力,T3的20分暴力,然后开始等死。

    (当时并没有意识到T3的随机数据还可以送20分,还有意外拿的水数据10分)

    抱头想了半天没有一点思路。想二分不知不觉想到了模拟上,我最近真是打模拟打傻了……

    然后T2xjb写了个骗分算法。

    最后十分钟对拍一下表现我不屈的灵魂!

    不到5分钟码出来随机数据生成器和对拍程序结果不知道哪里写挂了,到最后也没调出来。

    然后以为自己代码写挂了,心态瞬间崩溃。

    出成绩之后不敢看排行榜。闭着眼把进度条拉到最下面,偷偷睁眼看,呀没有我。

    一名一名往上翻,不是,不是,不是,woc我是不是没交啊。

    70分rank26。好吧,虽然炸了,但T3的50分确实是意外之喜。

    赛题题解

    T1:Star Way To Heaven

    二分答案确实是正解之一。不过不应该照着模拟去想。

    T80算法1:

    二分距离最小值,给每一对距离小于这个最小值的点建边。

    上边界设为0号点,下边界设为k+1号点,从上边界开始跑一趟dfs,如果能搜到k+1,则返回false,否则返回true

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<algorithm>
    #define rint register int
    using namespace std;
    int n,m,k,tot,first[60003];
    bool vis[60003];
    struct node{int x,y;}p[60003];
    struct node2{int u,v,nxt;}edge[600003<<1];
    inline double dist(int uu,int vv)
    {
        return (p[uu].x-p[vv].x)*(p[uu].x-p[vv].x)+
               (p[uu].y-p[vv].y)*(p[uu].y-p[vv].y);
    }
    inline void add(int uu,int vv)
    {
        edge[++tot]=(node2){uu,vv,first[uu]};
        first[uu]=tot;
    }
    inline void dfs(int x)
    {
        vis[x]=1;
        for(rint i=first[x];i;i=edge[i].nxt)
        {
            int y=edge[i].v;
            if(!vis[y])dfs(y);
        }
        return ;
    }
    inline bool check(double x)
    {
        tot=0;memset(first,0,sizeof(first));
        for(rint i=1;i<k;++i)
            for(rint j=i+1;j<=k;++j)
                if(dist(i,j)<4*x*x)
                    add(i,j),add(j,i);
        for(rint i=1;i<=k;++i)
        {
            if(p[i].y<2*x)add(0,i),add(i,0);
            if(p[i].y+2*x>m)add(i,k+1),add(k+1,i);
        }
        memset(vis,0,sizeof(vis));
        dfs(0);
        return !vis[k+1];
    }
    int main()
    {
        scanf("%d %d %d",&n,&m,&k);
        for(rint i=1;i<=k;++i)
            scanf("%d %d",&p[i].x,&p[i].y);
        double l=1,r=1e6;
        while(r-l>1e-11)
        {
            double mid=(l+r)/2;
            if(check(mid))l=mid;
            else r=mid;
        }
        printf("%.8lf",l);
        return 0;
    }
    T80算法1(其实是w50,请读者自行手开long long/懒.jpg)

    T80算法2:

    依旧是二分,check操作改为并查集实现。原理大致相同。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<algorithm>
    #define int long long
    #define rint register int
    using namespace std;
    int n,m,k,tot,first[60003],fa[6003];
    bool vis[60003];
    struct node{int x,y;}p[60003];
    inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline double dist(int uu,int vv)
    {
        return (p[uu].x-p[vv].x)*(p[uu].x-p[vv].x)+(p[uu].y-p[vv].y)*(p[uu].y-p[vv].y);
    }
    inline bool check(double x)
    {
        for(rint i=0;i<=k+1;++i)fa[i]=i;
        for(rint i=1;i<k;++i)
            for(rint j=i+1;j<=k;++j)
                if(dist(i,j)<4*x*x)
                {
                    int lx=find(i),ly=find(j);
                    if(lx!=ly)fa[lx]=ly;
                }
        for(rint i=1;i<=k;++i)
        {
            if(p[i].y<2*x)
            {
                int lx=find(0),ly=find(i);
                if(lx!=ly)fa[lx]=ly;
            }
            if(p[i].y+2*x>m)
            {
                int lx=find(k+1),ly=find(i);
                if(lx!=ly)fa[lx]=ly;
            }
        }
        return find(0)!=find(k+1);
    }
    signed main()
    {
        scanf("%lld %lld %lld",&n,&m,&k);
        for(rint i=1;i<=k;++i)
            scanf("%lld %lld",&p[i].x,&p[i].y);
        double l=1,r=1e6,mid;
        while(r-l>1e-11)
        {
            mid=(l+r)/2;
            if(check(mid))l=mid;
            else r=mid;
        }
        printf("%.8lf
    ",mid);
        return 0;
    }
    T80算法2

    AC算法:

    考虑如何对T80算法2进行优化。

    算法2的主要瓶颈在于并查集的合并中需要$(n^2)$搜一边,这样效率无疑是很低的。

    根据并查集的特点,我们不妨预处理出每一个点左上、左下、右上、右下四个方向上最近的点。

    不难发现,其他点若也能连接到该点,则一定能通过这四个点中的某一个连接到它。

    于是我们每次对每一个点进行合并时只需要扫这四个点就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<algorithm>
    #define int long long
    #define rint register int
    using namespace std;
    int n,m,k,tot,first[60003],fa[6003];
    int yh[6003][4];
    bool vis[60003];
    struct node{int x,y;}p[60003];
    inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline double dist(int uu,int vv)
    {
        return (p[uu].x-p[vv].x)*(p[uu].x-p[vv].x)+(p[uu].y-p[vv].y)*(p[uu].y-p[vv].y);
    }
    inline bool check(double x)
    {
        for(rint i=0;i<=k+1;++i)fa[i]=i;
        for(rint i=1;i<=k;++i)
            for(rint j=0;j<=3;++j)
            {
                if(!yh[i][j])continue;
                if(dist(i,yh[i][j])<4*x*x)
                {
                    int lx=find(i),ly=find(yh[i][j]);
                    if(lx!=ly)fa[lx]=ly;
                }
            }
                
        for(rint i=1;i<=k;++i)
        {
            if(p[i].y<2*x)
            {
                int lx=find(0),ly=find(i);
                if(lx!=ly)fa[lx]=ly;
            }
            if(p[i].y+2*x>m)
            {
                int lx=find(k+1),ly=find(i);
                if(lx!=ly)fa[lx]=ly;
            }
        }
        return find(0)!=find(k+1);
    }
    signed main()
    {
        scanf("%lld %lld %lld",&n,&m,&k);
        for(rint i=1;i<=k;++i)
            scanf("%lld %lld",&p[i].x,&p[i].y);
        for(rint i=1;i<=k;++i)
            for(rint j=1;j<=k;++j)
            {
                if(i==j)continue;
                int dis=dist(i,j);
                if(p[j].x<=p[i].x&&p[j].y<=p[i].y)
                    yh[i][0]=(dis<dist(yh[i][0],i))?j:yh[i][0];
                if(p[j].x>=p[i].x&&p[j].y<=p[i].y)
                    yh[i][1]=(dis<dist(yh[i][1],i))?j:yh[i][1];
                if(p[j].x>=p[i].x&&p[j].y>=p[i].y)
                    yh[i][2]=(dis<dist(yh[i][2],i))?j:yh[i][2];
                if(p[j].x<=p[i].x&&p[j].y>=p[i].y)
                    yh[i][3]=(dis<dist(yh[i][3],i))?j:yh[i][3];
            }
        double l=1,r=1e6,mid;
        while(r-l>1e-11)
        {
            mid=(l+r)/2;
            if(check(mid))l=mid;
            else r=mid;
        }
        printf("%.8lf
    ",mid);
        return 0;
    }
    Accepted 100 930 ms 604 KiB
  • 相关阅读:
    执行一个外部程序并等待他的结束
    打开WORD文档时提示“word无法启动转换器mswrd632 wpc”的解决方法
    WaitForSingleObject的用法
    Delphi CreateProcess WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件
    webservices传base64字串
    webservices传文件
    webservices 字节数组 Base64编码
    内存映射大文件
    文件分割合并
    move
  • 原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11369087.html
Copyright © 2011-2022 走看看