这次CF打得还不错,比上次好很多,做了4题,其中3题都是firstblood,E题最后30分钟才开始做,没做出来,B题wa了一次才ac,其间被网速杀了好几回,好在对最后的罚时影响并不是很大。
比赛提交记录:
最终比赛排名(含vp选手,共8445人)
在正式选手里排名123名(正式选手共3249人)
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;
}
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;
}
http://codeforces.com/contest/546/problem/C
两个士兵做游戏,他们手上有 n 张卡片,分别写着数字 1 到 n ,这些卡片有些在士兵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;
}
http://codeforces.com/contest/546/problem/D
问 a!b! 能分解成多少个质因数。
实际上就是问 b+1 到 a 这段范围内每个数字分解出的质因数的个数之和。我们可以在筛素数时记录每个数字分解出的质因数个数,然后求出前缀和即可得到答案。
#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;
}
http://codeforces.com/contest/546/problem/E
给你一张无向图,每个节点 i 上有 ai 个士兵。现在要让每个士兵进行一次迁移操作。迁移操作中,要么士兵选择在原结点不动,要么移动到相邻的结点上,问最终每个结点 i 上的士兵个数是否能达到 bi ,并输出一组可行解。
显然是个最大流问题。我们可以建立这样一个模型:
每个点拆成入点和出点。入点代表初始时每个点的状态,出点代表最终每个点的状态。源点向每个点 i 的入点连容量为 ai 的边,代表每个点最多可以向其他点输送 ai 个士兵。每个点 i 的出点向汇点连容量为 bi 的边,代表每个点最多只能从其他点接受 bi 个士兵。然后对于一条无向边 u−>v , u 的入点向 v 出点连容量正无穷的边, v 的入点向 u 出点连容量正无穷的边,代表 u 和 v 之间可以传送士兵。 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;
}