2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)(solve7/11)

题目链接:http://codeforces.com/gym/101572

B题

题意:给你n个人的第一棒的速度和其他棒的速度,然后让你输出最快的那个组合,输出时间和人。

思想:模拟

D题

题意:给你n个01串代表每个人的特征,现在让你求一个和他们长度相等但是和他们相似度最对的那个串。

思想:考虑最短路问题,将每个串拆出来k个差一位的子串,然后每个串开始不断的取反某一位,最后找到一个取反最多的。输出即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
char str[30];
int dist[1<<20];
int main()
{
    queue<int>q; 
    memset(dist,-1,sizeof(dist));
    int n,k;
    scanf("%d%d",&n,&k);    
    for(int i=0;i<n;i++)
    {
        scanf("%s",str);
        int ans=0;
        for(int i=0;i<k;i++)
            if(str[i]=='1')
                ans=ans+(1<<i); 
        q.push(ans);
        dist[ans]=0;
    }
    int ans=0;
    int maxx=0;
    while(!q.empty())
    {
        int temp=q.front();
        q.pop();
        for(int i=0;i<k;i++)
        {
            int T = temp^(1<<i);
            if(dist[T]!=-1)
                continue;
            q.push(T);
            dist[T]=dist[temp]+1;
            if(dist[T]>maxx)
            {
                maxx=dist[T];
                ans=T; 
            }
        }
    }
    for(int i=0;i<k;i++)
    {
        if(ans&(1<<i))
            printf("1");
        else
            printf("0"); 
    }
    printf("\n");
    return 0;   
}

E题

题意:给你一个n*m的图,每个点有一个权值 小于0为水高于0为干旱的地,现在将抽水机放到一个位置问你最多能抽多少水,直接bfs抽水机的点,比当前点小的变到跟当前一样大,因为最多抽到跟当前点一样多的水。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e2+10;
int vis[maxn][maxn];
ll Map[maxn][maxn];
ll dis[maxn][maxn];
int dir[8][2]={-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1};
struct node{
    int x;
    int y;
    ll valu;
    bool operator <(const node &a) const{
        return valu > a.valu;
    }
};
int main()
{
    int h,w;
    int x,y;
    scanf("%d%d",&h,&w);
    for(int i=1;i<=h;i++)
        for(int j=1;j<=w;j++)
            scanf("%lld",&Map[i][j]);
    scanf("%d%d",&x,&y); 
    priority_queue<node>q;
    q.push(node{x,y,Map[x][y]});
    vis[x][y]=1; 
    dis[x][y]=Map[x][y];
    while(!q.empty())
    {
        node u=q.top();
        q.pop();
        for(int i=0;i<8;i++)
        {
            int xx=dir[i][0]+u.x;
            int yy=dir[i][1]+u.y;
            if(xx>=1 && xx<=h && yy>=1 && yy<=w && vis[xx][yy]==0 && Map[xx][yy] < 0)
            {
                vis[xx][yy]=1;
                ll T = max(u.valu,Map[xx][yy]);
                dis[xx][yy]=T;
                q.push(node{xx,yy,T});
            }
        }       
    }
    ll ans=0;
    for(int i=1;i<=h;i++)
        for(int j=1;j<=w;j++)
            ans+=(-1)*dis[i][j];
    printf("%lld\n",ans);
    return 0;
}

G题

题意:给你n个队伍,m个过题记录。m行是某个队伍过了题然后的罚时。输出m行每次有人过题之后,1队的排名

思想:树状数组维护即可。树状数组维护当前点过题的人数。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
struct node{
    int x;
    int y;
}no[maxn];
int team[maxn];
int score[maxn];
int sum[maxn];
pair<int,int>P[2*maxn];
int n,m,cnt;
void add(int x,int valu)
{
    while(x<=cnt)
    {
        sum[x]+=valu;
        x+=(x&(-x)); 
    }
}
int ask(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=sum[x];
        x-=(x&(-x));
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    P[cnt++]=make_pair(0,0);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&no[i].x,&no[i].y);
        team[no[i].x]--;
        score[no[i].x]+=no[i].y;
        P[cnt++]=make_pair(team[no[i].x],score[no[i].x]);
    }
    sort(P,P+cnt);

    memset(team,0,sizeof(team));
    memset(score,0,sizeof(score)); 
    for(int i=0;i<m;i++)
    {
        int temp=lower_bound(P,P+cnt,make_pair(team[no[i].x],score[no[i].x]))-P+1; //减去上次影响 
        add(temp,-1);
        
        team[no[i].x]--;
        score[no[i].x]+=no[i].y;
        temp=lower_bound(P,P+cnt,make_pair(team[no[i].x],score[no[i].x]))-P+1;//加上现在的影响 
        add(temp,1);
        
        temp=lower_bound(P,P+cnt,make_pair(team[1],score[1]))-P+1;//计算队伍1前边有多少队伍 
        printf("%d\n",ask(temp-1)+1);//计算当前点前边的位置加上自己是最后一名 
    }
    return 0;
}

I题

题意:求一个有向图的最小环,输出路径。

思想:Floyd求最小环即可

 

J题

题意:给你n,m代表2遍的牙齿数量,问你牙齿总数或者是没有牙齿。

思想:模拟即可 特判下0 0

K题

题意:给你b,n,e代表三类人,分别是慢的中速快的,然后给你每个人的速度,然后给你(b+n+e)/2个皮划艇的速度系数,一个皮划艇的速度=皮划艇的速度系数*(第一个的速度+第二个的速度)

思想:二分+贪心

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define scanf(a) scanf("%d",&a);
using namespace std;
const double eps = 1e-7;
const int maxn=1e5+5;
int a[maxn];
int b,n,e,m,sb,sn,se;
struct node{
    int x;
    int y;
    int z;
    int value;
    bool operator < (const node &a)const {
        return value < a.value;
    }
}no[maxn];
int check(int mid)
{
    int bb=b,nn=n,ee=e;
    rep(i,1,m)
    {
        int cnt=0;
        double temp = (double)(mid) / (double)a[i];
        if(bb>=2)
            no[cnt++]={2,0,0,sb+sb};
        if(nn>=2)
            no[cnt++]={0,2,0,sn+sn};
        if(ee>=2)
            no[cnt++]={0,0,2,se+se};
        if(bb && nn)
            no[cnt++]={1,1,0,sb+sn};
        if(bb && ee)
            no[cnt++]={1,0,1,sb+se};
        if(nn && ee)
            no[cnt++]={0,1,1,sn+se};
        sort(no,no+cnt);
        int flag=0;
        rep(j,0,cnt-1)
        {
            if(temp - (double)(no[j].value) <= eps)
            {
                flag=1;
                bb=bb-no[j].x;
                nn=nn-no[j].y;
                ee=ee-no[j].z;
                break;
            }
        }
        if(flag==0)
            return 0; 
    } 
    return 1;
}
int main()
{   
    scanf(b);
    scanf(n);
    scanf(e);
    m = (b+n+e)/2;
     
    scanf(sb);
    scanf(sn);
    scanf(se);
    rep(i,1,m)
        scanf(a[i]); 
     
    int l=1;
    int r=1e9;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))
            l=mid+1;
        else
            r=mid-1;
    }
    printf("%d\n",r);
    return 0;
}

用ll也是OK的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值