Week 1 总结
训练篇 :
Round 1:
第一轮的题目都比较简单
1.工作安排
http://47.95.147.191/contest/5/problem/A
描述
Farmer John 有太多的工作要做!为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间。
他的工作日从0时刻开始,有个单位时间。在任一时刻,他都可以选择编号 1 ~N 的 N 项工作中的任意一项工作来完成。 因为他在每个单位时间里只能做一个工作,而每项工作又有一个截止日期,所以他很难有时间完成所有 N 个工作,虽然还是有可能。 对于第 i 个工作,有一个截止时间,如果他可以完成这个工作,那么他可以获利。
在给定的工作利润和截止时间下,FJ能够获得的利润最大为多少呢?
输入
输出
这个题目就是建立一个利润的最大生成树,然后从最后一天开始往前操作。因为每一天可以完成DDL是之后的工作而不能DDL是完成之前的。
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
struct VD{
long long d,p;
bool operator < (const VD & t)const{
return t.p > p;
}
}tm[110000];
bool cmp(const VD & i , const VD & j ){
return i.d>j.d;
}
long long ans=0,n;
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld %lld",&tm[i].d,&tm[i].p);
}
priority_queue<VD>q;
sort(tm+1,tm+n+1,cmp);
for(int i=1;i<=n;){
int ddl=tm[i].d;
while(tm[i].d==ddl){
q.push(tm[i]);
i++;
}
int td;
td=tm[i-1].d-tm[i].d;
while(td--){
if(!q.size()) break;
VD temp=q.top();
q.pop();
ans+=temp.p;
}
}
printf("%lld",ans);
return 0;
}
2.轻拍牛头
http://47.95.147.191/contest/5/problem/B
描述
今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏.
贝茜让N 头奶牛坐成一个圈.除了1号与N号奶牛外,i号奶牛与i−1号和i+1号奶牛相邻.N号奶牛与1号奶牛相邻.农夫约翰用很多纸条装满了一个桶,每一张包含了一个独一无二的1到的数字.
接着每一头奶牛i从桶中取出一张纸条.每头奶牛轮流走上一圈,同时拍打所有编号能整除在纸条上的数字的牛的头,然后做回到原来的位置.牛们希望你帮助他们确定,每一头奶牛需要拍打的牛.
输入
第1行包含一个整数N,接下来第2到N+1行每行包含一个整数.
输出
第1到N行,每行的输出表示第i头奶牛要拍打的牛数量.
题目意思其实就是找到所有奶牛中编号可以被整除的数量,于是就想到了筛法。
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
int n,a[110000],at[110000],st[1100000],s[1100000];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
at[i]=a[i];
st[a[i]]++;
}
sort(a+1,a+n+1);
int cnt=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=cnt;i++){
for(int j=1;j<=sqrt(a[i]);j++){
if(a[i]%j==0){
if(j*j==a[i]) {
s[a[i]]+=st[j];
}
else {
s[a[i]]+=st[j];
s[a[i]]+=st[a[i]/j];
}
}
}
}
for(int i=1;i<=n;i++){
printf("%d
",s[at[i]]-1);
}
return 0;
}
上面是第一遍的做法,因为不熟悉筛法所以做得有点蠢。。当时就看到怎么别人时间都是40多,我是260多。然后又想了一会才想到找素数中的用到的埃筛。
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
int n,a[1100000],x[1100000],s[1100000],maxt=0,num[1100000];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
maxt=max(maxt,a[i]);
x[i]=a[i];num[a[i]]++;
}
sort(a+1,a+n+1);
int cnt=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=cnt;i++)
for(int j=a[i];j<=maxt;j+=a[i]){
s[j]+=num[a[i]];
}
for(int i=1;i<=n;i++){
printf("%d
",s[x[i]]-1);
}
return 0;
}
更简洁还更快。。。
3.奶牛的比赛
http://47.95.147.191/contest/5/problem/C
描述
FJ的N 头奶牛们最近参加了场程序设计竞赛。在赛场上,奶牛们按1..N依次编号。每头奶牛的编程能力不尽相同,并且没有哪两头奶牛的水平不相上下,也就是说,奶牛们的编程能力有明确的排名。
整个比赛被分成了若干轮,每一轮是两头指定编号的奶牛的对决。如果编号为A的奶牛的编程能力强于编号为B的奶牛 ,那么她们的对决中,编号为A的奶牛总是能胜出。
FJ想知道奶牛们编程能力的具体排名,于是他找来了奶牛们所有 M 轮比赛的结果,希望你能根据这些信息,推断出尽可能多的奶牛的编程能力排名。比赛结果保证不会自相矛盾。
输入
输出
这个题目可以化成有向图的问题给出M条边,然后建图对于第i个点,记录有 l 个点可以到 i 就说明有 l 头奶牛排名比i高,然后记录 i 可以到达 r 个点,说明 i 排名比 r 头奶牛高。最后如果就说明这头牛的排名可以确定。问题就成了找路径,由于N很小,就可以想到用floyd找路径,然后开两个数组记录可以到每个点的点的个数和每个点可以到达的点的个数。
#include<stdio.h>
#include<iostream>
using namespace std;
int ans=0,t,n,m[110][110],l[110],r[110];
int main(){
for(int i=1;i<=105;i++)
for(int j=1;j<=105;j++){
m[i][j]=100000;
}
scanf("%d%d",&n,&t);
for(int i=1;i<=t;i++){
int a,b;
scanf("%d%d",&a,&b);
m[a][b]=1;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
m[i][j]=min(m[i][j],m[i][k]+m[k][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(m[i][j]<10000){
l[j]++;r[i]++;
}
}
for(int i=1;i<=n;i++){