Codeforces #304 Div 2 简要题解

来源:互联网 发布:vb if 编辑:程序博客网 时间:2024/05/21 13:57

比赛总结

这次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 6000000using 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 0x3f3f3f3fusing 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;}
0 0