2017-2018 ACM-ICPC, Nordic Collegiate Programming Contest

题目链接点击打开链接

B. Best Relay Team

直接模拟,按照后三棒成绩排序然后枚举第一棒的人选。

#include<bits/stdc++.h>
#define maxn 1050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n;
struct node
{
    char name[maxn];
    double x,y;
}e[maxn];
bool cmp(node a,node b)
{
    return a.y<b.y;
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%s%lf%lf",e[i].name,&e[i].x,&e[i].y);
    }
    sort(e,e+n,cmp);
    int k;
    double ans=1.0*INF;
    for(int i=0;i<n;i++)
    {
        double sum=e[i].x;
        int num=0;
        for(int j=0;j<n;j++)
        {
            if(i==j)continue;
            sum+=e[j].y;
            num++;
            if(num==3)break;
        }
        if(sum<ans)
        {
            ans=sum;
            k=i;
        }
    }
    printf("%lf\n%s\n",ans,e[k].name);
    int num=0;
    for(int i=0;i<n;i++)
    {
        if(i==k)continue;
        printf("%s\n",e[i].name);
        num++;
        if(num==3)break;
    }
    return 0;
}


D. Distinctive Character

求一个串使得其与给定各串的最大相似度最小。

一个串与本身的相似度最大,改变任意一位数可使其与原串的相似度-1。从给定的所有串出发bfs,这样可以保证每个新串在被扩展到时,它和扩展得到它的子串之间取到的是各串的最大相似度,且这个值即子母串之间的距离最小,这样就保证了最大相似度最小。最后遍历一遍扩展到的串找出最底层的任意一个串即可。时间复杂度O(2^k)。

#include<bits/stdc++.h>
#define maxn 35
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n,m;
char s[maxn];
int dis[1<<20];
queue<int>q;

int main()
{
    scanf("%d%d",&n,&m);
    memset(dis,-1,sizeof(dis));
    for(int i=0;i<n;i++)
    {
        scanf("%s",s);
        int tmp=0;
        for(int j=m-1;j>=0;j--)
        {
            tmp*=2;
            tmp+=(s[j]-'0');
        }
        dis[tmp]=0;
        q.push(tmp);
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=0;i<m;i++)
        {
            int v=u^(1<<i);
            if(dis[v]==-1)
            {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    int ans=0,maxx=0;
    for(int i=0;i<(1<<20);i++)
    {
        if(maxx<dis[i])
        {
            maxx=dis[i];
            ans=i;
        }
    }
    for(int i=0;i<m;i++)
    {
        printf("%d",ans%2);
        ans/=2;
    }
    printf("\n");
    return 0;
}


E. Emptying the Baltic

给定地形,求给定点处可有多少水流入。

从给定点向外bfs,保存每个点可外流的最大水深。扩展至一个新的点时,新点的最大外流量为前序点最大外流量与新点水深的较小值。最后将每个能扩展到的点的最大外流量相加即为答案。在bfs中使用优先队列,以保证每次拿出的状态都为前序点的最大外流量。

#include<bits/stdc++.h>
#define maxn 505
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n,m,sx,sy;
int ans[maxn][maxn];
int maze[maxn][maxn];
bool vis[maxn][maxn];
int pos[8][2]={1,0,0,1,-1,0,0,-1,1,1,1,-1,-1,-1,-1,1};
struct node
{
    int x,y;
    int h;
    bool friend operator < (const node a,const node b)
    {
        return a.h>b.h;
    }
};

bool judge(int x,int y)
{
    if(x>=1&&y>=1&&x<=n&&y<=m&&!vis[x][y])
        return true;
    return false;
}

void bfs(int sx,int sy)
{
    node st,now,nxt;
    priority_queue<node>q;
    st.x=sx,st.y=sy,st.h=maze[sx][sy];
    ans[sx][sy]=maze[sx][sy];
    vis[sx][sy]=1;
    q.push(st);
    while(!q.empty())
    {
        now=q.top();
        q.pop();
        for(int i=0;i<8;i++)
        {
            int fx=now.x+pos[i][0];
            int fy=now.y+pos[i][1];
            if(judge(fx,fy))
            {
                vis[fx][fy]=1;
                nxt.x=fx,nxt.y=fy;
                nxt.h=ans[fx][fy]=max(maze[fx][fy],now.h);
                q.push(nxt);
            }
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&maze[i][j]);
            if(maze[i][j]>=0)vis[i][j]=1;
        }
    }
    scanf("%d%d",&sx,&sy);
    bfs(sx,sy);
    ll sum=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(vis[i][j])
                sum+=(-1LL*ans[i][j]);
        }
    }
    printf("%I64d\n",sum);
    return 0;
}


G. Galactic Collegiate Programming Contest

模拟一个榜单,每次查询队伍1的名次。

维护所有名次在队伍1之前的队伍。如果其他队过题则更新,如果是队伍1过题就将此时在队伍1之后的队伍全部删掉。这种维护需要使用平衡树,这里选用STL中基于平衡树原理实现的multiset可以解决,每次查询输出的是multiset的大小。需要注意队伍1不在榜单时结果+1,以及队伍1和其他队伍并列时只保留队伍1。

#include<bits/stdc++.h>
#define maxn 100050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n,m,x,y;
struct node
{
    int num;
    int sum;
    int id;
    bool friend operator < (const node a,const node b)
    {
        if(a.num!=b.num)return a.num>b.num;
        else if(a.sum!=b.sum)return a.sum<b.sum;
        else return a.id<b.id;
    }
}e[maxn];
multiset<node>ans;
multiset<node>::iterator it;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        e[i].num=e[i].sum=0,e[i].id=i;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&x,&y);
        if(ans.count(e[x]))
            ans.erase(ans.find(e[x]));
        e[x].num++;
        e[x].sum+=y;
        ans.insert(e[x]);
        if(ans.count(e[1]))
        {
            while(!ans.empty()&&e[1]<*(--ans.end()))
                ans.erase(--ans.end());
            printf("%d\n",ans.size());
        }
        else printf("%d\n",ans.size()+1);
    }
    return 0;
}


I. Import Spaghetti

用Floyd算法求有向图中的最小环并输出其中一个最小环。

#include<bits/stdc++.h>
#define maxn 505
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n,m,minn;
int x,y,z;
string s;
map<string,int>mo;
map<int,string>om;
char t[maxn];
int fa[maxn][maxn],dis[maxn][maxn];
int maze[maxn][maxn],path[maxn];

void floyd()
{
    minn=INF;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(dis[i][j]==INF||maze[j][k]==INF||maze[k][i]==INF)
                    continue;
                if(dis[i][j]+maze[j][k]+maze[k][i]<minn)
                {
                    minn=dis[i][j]+maze[j][k]+maze[k][i];
                    x=i;
                    y=j;
                    z=k;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(dis[i][k]==INF||dis[k][j]==INF)
                    continue;
                if(dis[i][j]>dis[i][k]+dis[k][j])
                {
                    dis[i][j]=dis[i][k]+dis[k][j];
                    fa[i][j]=k;
                }
            }
        }
    }
}

void print_path(int u,int v)
{
    if(u==v)return;
    if(fa[u][v]==0)
        cout<<om[v]<<" ";
    else
    {
        print_path(u,fa[u][v]);
        print_path(fa[u][v],v);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        mo[s]=i;
        om[i]=s;
    }
    for(int i=0;i<=n;i++)
    {
        for(int j=0;j<=n;j++)
            maze[i][j]=dis[i][j]=INF;
    }
    memset(fa,0,sizeof(fa));
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        int u=mo[s];
        scanf("%d",&m);
        for(int j=0;j<m;j++)
        {
            scanf("%s",t);
            int v,pre=u;
            string a;
            while(getchar()!='\n')
            {
                cin>>a;
                if(a[a.length()-1]==',')
                    a.erase(a.end()-1);
                v=mo[a];
                //cout<<pre<<" "<<v<<endl;
                maze[pre][v]=dis[pre][v]=1;
                pre=v;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(maze[i][i]==1)
        {
            cout<<om[i]<<endl;
            return 0;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(maze[i][j]==1&&maze[j][i]==1)
            {
                cout<<om[i]<<" "<<om[j]<<endl;
                return 0;
            }
        }
    }
    floyd();
    if(minn==INF)printf("SHIP IT\n");
    else
    {
        cout<<om[x]<<" ";
        print_path(x,y);
        cout<<om[z]<<endl;
    }
    return 0;
}

J. Judging Moose

直接按照题意模拟。

#include<bits/stdc++.h>
#define maxn 1050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int a,b;

int main()
{
    scanf("%d%d",&a,&b);
    if(a==0&&b==0)printf("Not a moose\n");
    else if(a==b)printf("Even %d\n",a*2);
    else printf("Odd %d\n",max(a,b)*2);
    return 0;
}


K. Kayaking Trip

3种人两两搭配,每对有一个以某种方式计算出的权值,求最小权值的最大值。

二分答案,在每次验证时贪心地去取,在6种可能方案中取权值最小的合法方案,若每一对都能取出合法方案则该答案合法。

#include<bits/stdc++.h>
#define maxn 100050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int num[3],val[3];
int m,cnt,cur[3];
int w[maxn];
struct node
{
    int x,y;
    int sum;
}e[15];

bool judge(int x)
{
    for(int i=0;i<3;i++)cur[i]=num[i];
    for(int i=0;i<m;i++)
    {
        bool flag=0;
        for(int j=0;j<cnt;j++)
        {
            int p=e[j].x,q=e[j].y;
            if(cur[p]==0||cur[q]==0||w[i]*e[j].sum<x)continue;
            if(p==q&&cur[q]<2)continue;
            cur[p]--,cur[q]--;
            flag=1;
            break;
        }
        if(!flag)return false;
    }
    return true;
}

int main()
{
    for(int i=0;i<3;i++)scanf("%d",&num[i]);
    for(int i=0;i<3;i++)scanf("%d",&val[i]);
    m=(num[0]+num[1]+num[2])/2;
    for(int i=0;i<m;i++)
        scanf("%d",&w[i]);
    sort(w,w+m);
    cnt=0;
    for(int i=0;i<3;i++)
    {
        for(int j=i;j<3;j++)
        {
            e[cnt].x=i,e[cnt].y=j;
            e[cnt++].sum=val[i]+val[j];
        }
    }
    int l=0,r=INF,ans;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(judge(mid))
        {
            l=mid+1;
            ans=mid;
        }
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/80552598