1. 程式人生 > >2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)(solve7/11)

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

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的