zoukankan      html  css  js  c++  java
  • 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)

    Time:2018.4.29    8:30-13:30

    Link


    A

    题意

    给出总的路程L,普通速度a,喝咖啡速度后b,等咖啡时间t,咖啡有作用时间r,和n个咖啡厅的位置。买咖啡需要等待,喝咖啡时速度提升

    问在哪几个咖啡厅买咖啡,走完总路程所花的时间最短。可以扔掉咖啡,可以用手机预定咖啡。(L<=1e11,a,b<=200,t<=300,r<=1200,n<=5e5)

    假如不可以预定怎么做?

    分析

    Difficult

    ym:单调队列优化后dp???,留坑


    B    solved by ym

    题意

    四人接力跑,现分别给出n个人的第一棒和其他棒的时间,问选择四个人所用时间最小的时间,和对应的人(即方案) (n<=500)

    分析

    ym:首先直观的n^4暴力枚举,肯定不行,枚举第一棒贪心选取其余的即可

    时间复杂度O(nlogn)


    C

    题意

    分析

    大大大模拟,留坑 


    D     solved by ym&czh

    题意

    给出n个长度为m的0/1串,0和0或者1和1都是相同,问找出一个字符串使得与其他所有串相同的的最多的最少(n<=1e5,m<=20)

    分析

    ym:相同的数量尽可能少==不同的数量尽可能多,故可以将每个串看做一个点出发从其BFS找所有没有出现过的点,找一个different最大

             为什么different最大的是答案?我们BFS找到的每一个点都是原来的点最小different

    时间复杂度:O(k*2^k)

    czh:将每种字符串看作是一个点,总共2^20=1e6个点,以输入的n个字符串为起点,bfs找到最远的点

    这题用了个sting加map,运算起来特别慢,以后要首先分析时间复杂度

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <iostream>
    #include <cmath>
    #include <queue>
    #include <ctime>
    using namespace std;
    #define lson l,(l+r)/2,rt<<1
    #define rson (l+r)/2+1,r,rt<<1|1
    #define dbg(x) cout<<#x<<" = "<< (x)<< endl
    #define pb push_back
    #define fi first
    #define se second
    #define ll long long
    #define sz(x) (int)(x).size()
    #define pll pair<long long,long long>
    #define pii pair<int,int>
    #define pq priority_queue
    
    int d[1<<20];
    queue<int>q;
    int n,k;
    
    void bfs()
    {
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=0;i<k;i++)
            {
                int v=u^(1<<i);
                if(d[v]>d[u]+1)
                {
                    d[v]=d[u]+1;
                    q.push(v);
                }
            }
        }
    }
    
    int main()
    {
        string s;
        cin>>n>>k;
        for(int i=0;i<(1<<20);i++)
            d[i]=1<<20+1;
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            int sum=0;
            for(int ii=0;ii<k;ii++)
            {
                if(s[ii]=='1')
                sum+=(1<<(k-ii-1));
            }
            d[sum]=0;
            q.push(sum);
        }
        bfs();
        int id=0;
        for(int i=0;i<(1<<k);i++)
        {
            if(d[i]>d[id])
            {
                id=i;
            }
        }
        for(int i=0;i<k;i++)
        {
            if((id>>(k-i-1))&1)
                cout<<1;
            else
                cout<<0;
        }
        cout<<endl;
        return 0;
    }

    E    solved by ym&czh

    题意

    n*m 的地方,每个地方给出高度,所有 n*m 的地方有海拔为 0 的积水。 现在给出一个点作为排水口,每个地方的水可以往周围八个方向,且比它低的地方流。问最后会流走多少水

    分析

    ym:从排水口出发BFS,排水口是终点,每一个点每次只要可以进行类似松弛操作就update,但不幸,TEL,因为一个点可能被update很多次并且每次update后都要从其出发继续update

            优化:一个较为显然的是,每次从较低的从出发update最优,思想类似最短路,每次从边权最小的出发

            裸的BFS找最短路适用于边权都一样的,才能保证复杂度为O(v+e),因为每个点只会访问一次(第一次访问的一定是最小的),回到此题,高度和边权类似,但“边权”不一样

            所以时间复杂度会爆炸

    时间复杂度(nlogn)

    #include<bits/stdc++.h>
    #define ll long long
    #define pb push_back
    using namespace std;
    const int mod=1e9+7;
    
    const int dx[]={1,-1,0,0,1,1,-1,-1};
    const int dy[]={0,0,-1,1,-1,1,1,-1};
    
    int mp[505][505];
    int h,w,ans[505][505];
    int sx,sy;
    
    struct node
    {
        int x,y,h;
        friend bool operator<(node a,node b)
        {
            return a.h>b.h;
        }
    };
    
    bool ok(int x,int y)
    {
        if(x>=1&&x<=h&&y>=1&&y<=w)
            return true;
        return false;
    }
    void bfs(int x,int y,int h)
    {
        priority_queue<node>q;
        q.push({x,y,h});
        while(!q.empty())
        {
            node k=q.top();
            q.pop();
            for(int i=0;i<8;i++)
            {
                int xx=k.x+dx[i];
                int yy=k.y+dy[i];
                if(ok(xx,yy) && ans[xx][yy]>max(k.h,mp[xx][yy]))
                {
                    ans[xx][yy]=max(k.h,mp[xx][yy]);
                    q.push({xx,yy,ans[xx][yy]});
                }
            }
        }
    
    }
    
    int main()
    {
        scanf("%d%d",&h,&w);
        for(int i=1;i<=h;i++)
        {
            for(int j=1;j<=w;j++)
            {
                scanf("%d",&mp[i][j]);
                if(mp[i][j]>0)
                    mp[i][j]=0;
            }
        }
        scanf("%d%d",&sx,&sy);
        if(mp[sx][sy]==0)
        {
            cout<<0<<endl;
            return 0;
        }
        ans[sx][sy]=mp[sx][sy];
        bfs(sx,sy,mp[sx][sy]);
        ll answer=0;
        for(int i=1;i<=h;i++)
        {
            for(int j=1;j<=w;j++)
            {
                answer+=ans[i][j];
            }
        }
        cout<<-answer<<endl;
        return 0;
    }

    F

    Different


    G     solved by czh&ym

    题意

    有n个队伍,m条事件。每条事件代表a队伍通过一个题目,罚时为b。对于每条事件,输出,1号队伍的排名。 

    分析

    czh:用一个set数组储存每个过题数的队伍编号。对于每次询问,如果不是一号队伍,只需要挪动set中的元素,如果是一号队伍,统计这次过题超过的队伍数,并挪动

    ym:写了暴力复杂度爆炸成功TLE,还好帮忙czh找出错误样例

    花絮:tm不能当变量名啊!!!

    时间复杂度:由于和1同题数最多的队伍很多,并且修改的是1后就不想同的,所以很快(我算不出qaq)


    H

    题意

    分析

    ym:听说是极角排序后最大流,滚去学


    I     solved by ym

    题意

    问题可以简化为:给出n个点的有向图,问最小环的路径(即方案)(n<=500)

    分析

    ym:dfs标记找环??X掉)       从每个点出发BFS,求出最短路的过程中记录前驱即可,既然都是环,随便输出都行      /     当然Floyd也可以

    dfs找环存在的问题:由于序号标记是按照dfs顺序,故无法得出环的边数,但可以求是否存在环

    时间复杂度O(n*(n+m))

    #include<bits/stdc++.h>
    using namespace std;
    
    
    vector<int>v[502],rv[502];
    unordered_map<string,int>mp;
    int d[502];
    int pre[502];
    char name[502][10];
    
    void bfs(int st)
    {
        queue<int>q;
        q.push(st);
        d[st]=0;
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            for(int i=0;i<int(v[now].size());i++)
            {
                int to=v[now][i];
                if(d[to]>d[now]+1)
                {
                    d[to]=d[now]+1;
                    pre[to]=now;
                    q.push(to);
                }
            }
        }
    
    }
    
    int main()
    {
        int n;
        string s;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",name[i]);
            mp[name[i]]=i;
        }
        int x=n,k;
        while(x--)
        {
            cin>>s;
            scanf("%d",&k);
            int u=mp[s];
            while(k--)
            {
              cin>>s;
                while(1)
                {
                    cin>>s;
                int len=s.length();
                if(s[len-1]==',')
                {
                    s.resize(len-1);
                    int to=mp[s];
                    v[to].push_back(u);
                    rv[u].push_back(to);
                }
                else
                {
                    int to=mp[s];
                    v[to].push_back(u);
                    rv[u].push_back(to);
                    break;
                }
                }
            }
        }
        int ans=1e9,st,ed;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                d[j]=1e9;
            bfs(i);
            for(int j=0;j<int(rv[i].size());j++)
            {
                int u=rv[i][j];
                if(ans>d[u]+1)
                {
                    ans=d[u]+1;
                    st=i;
                    ed=u;
                }
            }
        }
        if(ans==1e9)
        {
            puts("SHIP IT");
            return 0;
        }
        else
        {
    
            for(int j=1;j<=n;j++)
                d[j]=1e9;
            bfs(st);
            int now=ed;
            while(now!=st)
            {
                printf("%s ",name[now]);
                now=pre[now];
            }
            printf("%s
    ",name[now]);
        }
        return 0;
    }

    J   solved by ym

    题意

    签到,按题意模拟即可


    K  solved by ym

    题意

    给出三种人的数量b,n,e,每种人有一个Sb,Sn,Se,现两人一组,给出(b+n+e)/2个vi,问要所有组最小的最大方案,输出最小的最大

    分析

    ym:二分答案后贪心暴力check

    时间复杂度O(nlogn)

    #include<bits/stdc++.h>
    using namespace std;
    
    int B,N,E;
    int a[1000005],w[5],m[5];
    int sb,sn,se,n;
    
    bool check(int mid)
    {
        int mm[5];
        mm[1]=m[1], mm[2]=m[2], mm[3]=m[3];
        for(int i=1;i<=n;i++)
        {
            int jj=-1,kk=-1;
            int need=mid/a[i]+(mid%a[i]>0);
            for(int j=1;j<=3;j++)
            {
                for(int k=j;k<=3;k++)
                {
                    int num=1;
                    if(j==k) num=2;
                    if(jj==-1&&kk==-1)
                    {
                       if(mm[j]>=num && mm[k]>=num && (w[j]+w[k])>=need)
                       {
                           jj=j;
                           kk=k;
                       }
                    }
                    else
                    {
                        if(mm[j]>=num && mm[k]>=num && (w[j]+w[k])>=need && (w[j]+w[k])<(w[jj]+w[kk]))
                        {
                            jj=j;
                            kk=k;
                        }
                    }
                }
            }
            if(jj==-1)
                return false;
            mm[jj]-=1;
            mm[kk]-=1;
        }
        return true;
    }
    
    int main()
    {
        scanf("%d%d%d",&m[1],&m[2],&m[3]);
        scanf("%d%d%d",&w[1],&w[2],&w[3]);
        n=(m[1]+m[2]+m[3])/2;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        int l=1,r=1e9;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(check(mid)) l=mid;
            else r=mid-1;
        }
        printf("%d
    ", l);
        return 0;
    }

    Summary

    Ym

    Czh:

  • 相关阅读:
    xCode中怎样保存自己的代码块
    2015-03-13---抽象工厂(附代码),
    java nio 缓冲区(一)
    MFC获取各个窗体(体)之间的指针(对象)
    自己动手写神经网络,自己真的能够动手写神经网络嘛?
    Android招財进宝手势password的实现
    QQ三方登录
    UVA 10561
    Vagi单点登录1.0
    《反脆弱》:软件业现成的鲁棒性(Robust)换了个说法变成了作者的发明,按作者的理论推导出许多可笑愚蠢的原则来
  • 原文地址:https://www.cnblogs.com/Deadline/p/8969639.html
Copyright © 2011-2022 走看看