HLJU@贪心练习 解题报告

来源:互联网 发布:阿里云 idc资质 编辑:程序博客网 时间:2024/05/29 21:35

传送门:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=76975#overview

第一题:

这个题目由于学长已经讲了方法了,而且大家都做了,我就大概提一点吧。

就是做题的话要先按照    罚时/时间    按照从大到小排序   先做每分钟罚时多的

而且学长还证明了这个题目 我就直接给代码给大家把:


#include<cstdio>#include<algorithm>using namespace std;struct Arr{    int a,b;}s[100005];bool cmp(Arr x,Arr y){    return x.a*y.b<y.a*x.b;}int main(void){    int n,i;    long long sum,time;    while(scanf("%d",&n)!=EOF){        for(i=0;i<n;i++)            scanf("%d",&s[i].a);        for(i=0;i<n;i++)            scanf("%d",&s[i].b);        sort(s,s+n,cmp);        for(i=0,sum=0,time=0;i<n;i++){            time+=s[i].a;            sum+=s[i].b*time;        }        printf("%I64d\n",sum);    }}

第二题:

             这个题目学长也讲了规律    10  的话怎么样也要被看到一次  00 1101都不会被看到   所以就数有几个 10 序列就好  例如  10110  就有 4 个这样的序列  

#include<cstdio>int main(void){    int n,i,cnt,a;    long long  sum;    while(scanf("%d",&n)!=EOF){        for(i=0,sum=0,cnt=0;i<n;i++){            scanf("%d",&a);            if(a==1) cnt++;            else sum+=cnt;        }        printf("%I64d\n",sum);    }}



第三题:

                  题意:有n个人 每个人是第几次参加比赛,问最多能组成多少个ACM队伍(有且仅有3人,且比赛过程中不能换人,队伍确定下来就一直打比赛)去参加k次比赛

                  这个题目就简单了  就是计数  给出代码:

#include<cstdio>int main(void){    int i,n,cnt,k,shu,a;    while(scanf("%d %d",&n,&k)!=EOF){        shu=5-k;        for(i=0,cnt=0;i<n;i++){            scanf("%d",&a);            if(a<=shu) cnt++;        }            printf("%d\n",cnt/3);    }

第四题:

               题意:地图上有 n 个点,n个点都是矿产,一个正方形的城市要把这些点全部包含,问城市最小的面积

               分析:每次输入都更新一下最小的x坐标最大的x坐标和最小的y坐标最大的y坐标就好了哦      long long 和%I64d要注意哈 

#include<cstdio>#include<algorithm>using namespace std;int main(void){    long long wide,high;    int i,j,n,a,b,x1,x2,y1,y2;    while(scanf("%d",&n)!=EOF){        scanf("%d %d",&a,&b);        x1=x2=a,y1=y2=b;        for(i=1;i<n;i++){            scanf("%d %d",&a,&b);            x1=min(x1,a);            x2=max(x2,a);            y1=min(y1,b);            y2=max(y2,b);        }        wide=x2-x1;        high=y2-y1;        printf("%I64d\n",wide>high?wide*wide:high*high);    }}


第五题:

    题意:这个人想浇水 然后呢,他的水壶比较特殊,一次可以浇 k 这个范围的植物,每次浇水植物都会长高,问你 n 天(一天只能浇一次水)后,所有可能的最矮的植物的高度最大。

            分析:这个题目就是二分枚举了,其实这个题目就是用二分做(贪心其实是次要的) 主要就是二分找到第一个不满足的花的高度,之后输出高度减一就好了,二分的话大家应该都会写,大家的主要障碍就是怎么去判断二分到的这个值满不满足。因为的话假如 k 大的异常,那么就是 O(N*N)的算法了,就会超时,学长和我们说了一种标记法

就是从左到右扫一遍数组,假如有一颗植物比枚举到的这个数要小的时候它就要被浇水了吧,而且当我们从左到右扫的时候前面的高度就一定大于等于我们枚举的数了对吧?

所以我们每次浇水的话就往后面浇水,在这个浇水的位置标记为 1 ,在加 k 的地方就标记为 -1 ,这样代表浇一次水,但是假如一颗植物比我们枚举到的数小好多的话也是O(n*n)的算法了,所以我们干脆就一次把水浇好  就标记为    mid-high[i] ,第k个地方就标记为 -mid-high[i],之后每次遍历点的时候就加上这些标记的值就好了。

 我都敲累了,给出代码,好好理解理解,我的变量名设的很人性话,大家应该都看得懂。

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;long long a[100005],b[100005];int main(void){    int i,j,n,num,wide,use,grow;    long long high,left,right,mid;    while(scanf("%d %d %d",&n,&num,&wide)!=EOF){        high=0;        for(i=0;i<n;i++){            scanf("%d",&a[i]);            high=max(high,a[i]);        }        left=0;right=high+num+1;        while(left<right){            mid=(left+right)/2;            memset(b,0,sizeof(b));            for(i=0,grow=0,use=0;i<n;i++){                grow+=b[i];                if(a[i]+grow<mid){                    b[(i+wide)>=n?n:(i+wide)]=a[i]+grow-mid;                    use+=mid-(a[i]+grow);                    grow+=mid-(a[i]+grow);                }                if(use>num)                    break;            }            if(use<=num)                left=mid+1;            else right=mid;        }        printf("%I64d\n",left-1);    }}



第六题:

题意:就是有一个人想拿奖学金,但是呢,每一科通过其他方式加上原来的分数不能超过限制,然后的话就是他每门科目的平均分是 k ,然后补第 i 科想加一分的话就要写 b 篇论文,问你,他想得到奖学金,至少还要写几篇论文。

分析:我们按照b排序,从小到大排,能加的分数不超过限制的话,就一直写这个论文呗,就这样,

代码如下:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct node{    long long  a,b;}s[100005];bool cmp(node x,node y){    return x.b<y.b;}int main(void){    long long t,i,n,high,ave,sum,cnt;    while(scanf("%I64d %I64d %I64d",&n,&high,&ave)!=EOF){        t=n*ave;        cnt=0;        for(i=0,sum=0;i<n;i++){            scanf("%I64d %I64d",&s[i].a,&s[i].b);            t-=s[i].a;        }        sort(s,s+n,cmp);        for(i=0,sum=0;i<n;i++){            if(t<=0)                break;            if(s[i].a<high){                if(high-s[i].a>t){                    cnt+=s[i].b*t;                    break;                }                else{                    cnt+=s[i].b*(high-s[i].a);                    t-=(high-s[i].a);                }            }        }        printf("%I64d\n",cnt);    }}
第七题:

题意:有客人到餐馆去吃饭,我们事先知道他们要花多少钱,知道我们的座位多大,问怎么坐才可以盈利最大,输出盈利最多的方案。

分析:我们按照顾客花钱的顺序排序,钱花的多的我们当然得留下来啊?!然后依次遍历就好啦。

给出代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct node{    long long  a,b;}s[100005];bool cmp(node x,node y){    return x.b<y.b;}int main(void){    long long t,i,n,high,ave,sum,cnt;    while(scanf("%I64d %I64d %I64d",&n,&high,&ave)!=EOF){        t=n*ave;        cnt=0;        for(i=0,sum=0;i<n;i++){            scanf("%I64d %I64d",&s[i].a,&s[i].b);            t-=s[i].a;        }        sort(s,s+n,cmp);        for(i=0,sum=0;i<n;i++){            if(t<=0)                break;            if(s[i].a<high){                if(high-s[i].a>t){                    cnt+=s[i].b*t;                    break;                }                else{                    cnt+=s[i].b*(high-s[i].a);                    t-=(high-s[i].a);                }            }        }        printf("%I64d\n",cnt);    }}


最后一题:

题意:就是这里有一堆任务要求执行,CPU想要它的主频最低该多低。

分析:看到这个题目就知道是二分了,显然,这个想法也很正确,但是后面的判断却难了我好久好久,最后我也是看别人的代码才知道的。。

这个就要用到优先队列了,其实这个也很方便(STL中有这个现成的,我们只需要用就好啦)这里我们就要定义一个优先级,这个优先级是先结束的程序我先做,就是每次我都取出队列里面的最先结束的那个程序,但是假如我发现在某一个时间我从队列中取出的任务的结束的时间要小于我现在的时间就可以到终点了,因为这样的话我怎么样都无法完成任务优先级的定义下次我会找个机会给大家讲讲怎么定义和使用,其实很简单的。

这个题目我就先给出代码给大家,有不懂的可以问我

#include<cstdio>#include<cstring>#include<queue>#include<algorithm>using namespace std;struct task{    int a,b,c;    bool operator < (const task &a) const{        return b > a.b;    }}s[10005],t;int cmp(task x,task y){    return x.a<y.a;}int n;bool check(int mid){    int i,num,k;    priority_queue<task> Q;    k=0;    for(i=0;i<20005;i++){        while(k!=n&&s[k].a<i) Q.push(s[k++]);        num=mid;        while(num!=0){            if(!Q.empty()){                t=Q.top();                Q.pop();                if(t.b<i) return false;                if(t.c>num){                    t.c-=num;                    num=0;                    Q.push(t);                }                else                    num-=t.c;            }            else break;        }    }    if(Q.empty()&&k==n)        return true;    else return false;}int main(void){    int T,i,j,m,left,right,mid;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        for(i=0;i<n;i++)            scanf("%d %d %d",&s[i].a,&s[i].b,&s[i].c);        sort(s,s+n,cmp);        left=0;right=1005*10000;        while(left<right){            //priority_queue<task,vector<task>,cmp2> Q;            mid=(left+right)/2;            if(check(mid))                right=mid;            else left=mid+1;        }        printf("%d\n",left);    }}





0 0