Codeforces #304 Div 2 簡要題解

比賽總結

這次CF打得還不錯,比上次好很多,做了4題,其中3題都是firstblood,E題最後30分鐘纔開始做,沒做出來,B題wa了一次才ac,其間被網速殺了好幾回,好在對最後的罰時影響並不是很大。
比賽提交記錄:
這裏寫圖片描述
最終比賽排名(含vp選手,共8445人)
這裏寫圖片描述
在正式選手裏排名123名(正式選手共3249人)

A. Soldier and Bananas

題目鏈接

http://codeforces.com/contest/546/problem/A

題目大意

買香蕉要花wi=1ik 元錢,你手上目前有n 元錢,問還要借多少錢,纔夠買香蕉。

思路

水題,不說了

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

typedef long long int LL;

int main()
{
    LL k,w,n;
    scanf("%I64d%I64d%I64d",&k,&n,&w);
    LL need=(k+w*k)*w/2-n;
    if(need<=0) printf("0\n");
    else printf("%I64d\n",need);
    return 0;
}

B. Soldier and Badges

題目鏈接

http://codeforces.com/contest/546/problem/B

題目大意

給你一個序列,每次操作你可以對一個元素加1,問最少經過多少次操作,才能使所有元素互不相同

思路

首先對序列進行排序,排序後的序列裏,我們從左到右掃一遍所有元素,若當前的元素小於等於它左邊的元素,就讓當前的元素變成它左邊的元素大小+1,如此反覆,顯然可以得到正確答案

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

typedef long long int LL;

int n;
LL val[4000];

int main()
{
    LL ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%I64d",&val[i]);
    sort(val+1,val+n+1);
    for(int i=2;i<=n;i++)
        if(val[i]<=val[i-1])
            {ans+=val[i-1]-val[i]+1,val[i]=val[i-1]+1;}
    printf("%I64d\n",ans);
    return 0;
}

C. Soldier and Cards

題目鏈接

http://codeforces.com/contest/546/problem/C

題目大意

兩個士兵做遊戲,他們手上有n 張卡片,分別寫着數字1n ,這些卡片有些在士兵A手上,有些在士兵B手上,這些卡片分成了兩個紙牌堆。每回合遊戲,A和B分別把他們堆頂的紙牌拿來對比,誰的紙牌數字大,誰獲勝。勝者將兩個紙牌都放入自己的牌堆的堆底。判斷最後誰獲勝,比賽要經過多少回合才結束。若比賽永遠不結束,輸出-1

思路

由於n 很小,因此我們直接模擬遊戲過程即可。但是判斷比賽是否可以結束比較麻煩,我們可以對兩堆紙牌的數字進行hash,然後判重即可,若當前回合裏兩堆紙牌的狀態曾經出現過,則顯然比賽是永遠無法結束的。

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

using namespace std;

typedef long long int LL;

int n;
LL val[4000];

int main()
{
    LL ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%I64d",&val[i]);
    sort(val+1,val+n+1);
    for(int i=2;i<=n;i++)
        if(val[i]<=val[i-1])
            {ans+=val[i-1]-val[i]+1,val[i]=val[i-1]+1;}
    printf("%I64d\n",ans);
    return 0;
}

D. Soldier and Number Game

題目鏈接

http://codeforces.com/contest/546/problem/D

題目大意

a!b! 能分解成多少個質因數。

思路

實際上就是問b+1a 這段範圍內每個數字分解出的質因數的個數之和。我們可以在篩素數時記錄每個數字分解出的質因數個數,然後求出前綴和即可得到答案。

代碼

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <queue>

#define MAXN 6000000

using namespace std;

typedef long long int LL;

bool isPrime[MAXN];
int sum[MAXN];
int cnt[MAXN];

void GetPrime()
{
    memset(isPrime,true,sizeof(isPrime));
    isPrime[0]=isPrime[1]=false;
    for(int i=2;i<MAXN;i++)
    {
        if(!isPrime[i]) continue;
        for(int j=i+i;j<MAXN;j+=i)
        {
            isPrime[j]=false;
        }
        for(LL j=(LL)i;j<MAXN;j*=(LL)i)
            for(LL t=j;t<MAXN;t+=j)
                cnt[t]++;
    }
    for(int i=1;i<MAXN;i++)
        sum[i]=sum[i-1]+cnt[i];
}

int T;

int main()
{
    /*for(int i=1;i<MAXN;i++)
    {
        int tmp=i,nowt=0;
        for(int i=2;i*i<=tmp;i++)
        {
            while(!tmp%i) tmp/=i,nowt++;
        }
        sum[i]+=nowt;

    }*/
    GetPrime();
    //cout<<tot<<endl;
    scanf("%d",&T);
    while(T--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",sum[a]-sum[b]);
    }
    return 0;
}

E. Soldier and Traveling

題目鏈接

http://codeforces.com/contest/546/problem/E

題目大意

給你一張無向圖,每個節點i 上有ai 個士兵。現在要讓每個士兵進行一次遷移操作。遷移操作中,要麼士兵選擇在原結點不動,要麼移動到相鄰的結點上,問最終每個結點i 上的士兵個數是否能達到bi ,並輸出一組可行解。

思路

顯然是個最大流問題。我們可以建立這樣一個模型:
每個點拆成入點和出點。入點代表初始時每個點的狀態,出點代表最終每個點的狀態。源點向每個點i 的入點連容量爲ai 的邊,代表每個點最多可以向其他點輸送ai 個士兵。每個點i 的出點向匯點連容量爲bi 的邊,代表每個點最多隻能從其他點接受bi 個士兵。然後對於一條無向邊u>vu 的入點向v 出點連容量正無窮的邊,v 的入點向u 出點連容量正無窮的邊,代表uv 之間可以傳送士兵。u 的入點和其自身的出點連容量正無窮的邊,代表u 點上可以留下一些士兵。

其實這樣的一個模型很好建立,但是我還是太弱了,考場上沒想出來。。。

代碼

#include <sstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXV 1000
#define MAXE 3000
#define MAXN 1000
#define INF 0x3f3f3f3f

using namespace std;

int S=MAXV-2,T=MAXV-1;

struct edge
{
    int u,v,cap,next;
}edges[MAXE];

int head[MAXV],nCount=1;

void AddEdge(int U,int V,int C)
{
    edges[++nCount].u=U;
    edges[nCount].v=V;
    edges[nCount].cap=C;
    edges[nCount].next=head[U];
    head[U]=nCount;
}

void add(int U,int V,int C)
{
    AddEdge(U,V,C);
    AddEdge(V,U,0);
}

int layer[MAXV],q[MAXE*2];

bool CountLayer()
{
    memset(layer,-1,sizeof(layer));
    int h=0,t=1;
    q[h]=S;
    layer[S]=1;
    while(h<t)
    {
        int u=q[h++];
        for(int p=head[u];p!=-1;p=edges[p].next)
        {
            int v=edges[p].v;
            if(layer[v]==-1&&edges[p].cap)
            {
                layer[v]=layer[u]+1;
                q[t++]=v;
            }
        }
    }
    return layer[T]!=-1;
}

int DFS(int u,int flow)
{
    if(u==T) return flow;
    int used=0;
    for(int p=head[u];p!=-1;p=edges[p].next)
    {
        int v=edges[p].v;
        if(layer[v]==layer[u]+1&&edges[p].cap)
        {
            int tmp=DFS(v,min(flow-used,edges[p].cap));
            used+=tmp;
            edges[p].cap-=tmp;
            edges[p^1].cap+=tmp;
            if(used==flow) return used;
        }
    }
    if(!used) layer[u]=-1;
    return used;
}

int Dinic()
{
    int maxflow=0;
    while(CountLayer())
        maxflow+=DFS(S,INF);
    return maxflow;
}

int n,m;
int a[MAXV],b[MAXV];
bool inX[MAXV];
int vec[MAXV][MAXV];
int rest[MAXV];

int main()
{
    memset(head,-1,sizeof(head));
    int sumA=0,sumB=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&b[i]);
    for(int i=1;i<=n;i++)
    {
        add(S,i,a[i]);
        add(i,i+n,INF); //!!!!
        add(i+n,T,b[i]);
        sumA+=a[i];
        sumB+=b[i];
    }
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v+n,INF);
        add(v,u+n,INF);
    }
    if(sumA!=sumB)
    {
        printf("NO\n");
        return 0;
    }
    int mf=Dinic();
    if(mf!=sumB)
    {
        printf("NO\n");
        return 0;
    }
    printf("YES\n");
    for(int p=2;p<=nCount;p+=2)
    {
        if(edges[p].u==S||edges[p].u==T||edges[p].v==S||edges[p].v==T) continue;
        vec[edges[p].u][edges[p].v-n]=edges[p^1].cap;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            printf("%d ",vec[i][j]);
        }
        printf("\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章