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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章