模板题——贪心(2)

1.合并果子

【哈夫曼树】

#include <bits/stdc++.h>

using namespace std;
int n;
int main()
{
    cin>>n;
    priority_queue<int, vector<int >,greater<int> >heap;
    int x;
    while(n--)
    {
        cin>>x;
        heap.push(x);
    }
    int res=0;
    while(heap.size()>1)
    {
        int a=heap.top();heap.pop();
        int b=heap.top();heap.pop();
        res+=a+b;
        heap.push(a+b);
    }
    printf("%d\n",res);
    return 0;
}

2.耍杂技的牛

结论:按照wi+si从小到大的顺序排,得到的最大危险系数一定最小

#include <bits/stdc++.h>

using namespace std;
typedef pair<int ,int> PII;
const int N=50010;
int n;
PII cow[N];
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int s,w;
        scanf("%d%d",&w,&s);
        cow[i]={w+s,w};
    }
    sort(cow,cow+n);//pair按照第一位排序
    int res=-2e9,sum=0;
    for(int i=0;i<n;i++)
    {
        int s=cow[i].first-cow[i].second,w=cow[i].second;
        res=max(res,sum-s);
        sum+=w;
    }
    printf("%d\n",res);
    return 0;
}

3.1055. 股票买卖 II

买股票的贪心策略:看相邻两天,如果后一天>前一天,则交易一次

#include <bits/stdc++.h>

using namespace std;
const int N=100010;
int price[N];
int n;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&price[i]);
    int cnt=0;
    for(int i=1;i+1<=n;i++)
    {
        int dt=price[i+1]-price[i];
        if(dt>0) cnt+=dt;
    }
    printf("%d\n",cnt);
    return 0;
}

4.122. 糖果传递

需要一系列的推到证明转化成仓库选址的模型

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N=1000010;
int n;
int a[N];
LL c[N];
int main()
{
    scanf("%d",&n);
    LL sum=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    //sum变成平均数,下面c[i]的步骤按照推导过程来求
    sum/=n;
    for(int i=n;i>1;i--)
    {
        c[i]=c[i+1]+sum-a[i];
    }
    c[1]=0;
    //仓库选址中的求各个点到中位数距离的步骤
    sort(c+1,c+n+1);
    LL res=0;
    for(int i=1;i<=n;i++) res+=abs(c[i]-c[(n+1)/2]);
    printf("%lld\n",res);
    return 0;
}

5.1235.付账问题

贪心策略:将每个同学手里的钱排序,如果<平均值,就有多少付多少,不足的平摊到剩下比他大的所有同学身上;如果>平均值,就付平均值

#include <bits/stdc++.h>

using namespace std;
const int N=500010;
int n;
int a[N];
int main()
{
    long double s;
    cin>>n>>s;
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    sort(a,a+n);
    long double res=0,avg=s/n;
    for(int i=0;i<n;i++)
    {
        double cur=s/(n-i);
        if(a[i]<cur) cur=a[i];
        res+=(cur-avg)*(cur-avg);
        s-=cur;
    }
    printf("%.4lf\n",sqrt(res/n));
    return 0;
}

6.1239. 乘积最大

#include <bits/stdc++.h>

using namespace std;
const int N=100010,mod=1000000009;
int n,k;
int a[N];
typedef long long LL;
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    sort(a,a+n);
    int res=1;
    int l=0,r=n-1;
    int sign=1;//定义符号
    if(k%2)//先判断特殊情况即k为奇数
    {
        res=a[r--];//取出最大的一个负数
        k--;
        if(res<0)//所有数均为负数的情况
            sign=-1;
    }
    while(k)
    {
        LL x=(LL)a[l]*a[l+1],y=(LL)a[r-1]*a[r];//左右两侧均成对取数
        //哪边大取哪边
        if(x*sign>y*sign)
        {
            res=x%mod*res%mod;
            l+=2;
        }
        else
        {
            res=y%mod*res%mod;
            r-=2;
        }
        k-=2;
    }
    printf("%d\n",res);
    return 0;
}

7.1248.灵能传递

超级难,我只是刚刚看懂/(ㄒoㄒ)/~~

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N=300010;
int n;
LL a[N],s[N];
bool st[N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        s[0]=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&a[i]);
            s[i]=s[i-1]+a[i];
        }
        LL s0=s[0],sn=s[n];
        if(s0>sn)
            swap(s0,sn);
        sort(s,s+n+1);
        //寻找s0和sn的位置
        for(int i=0; i<=n; i++)
            if(s[i]==s0)
            {
                s0=i;
                break;
            }
        for(int i=n; i>=0; i--)
            if(s[i]==sn)
            {
                sn=i;
                break;
            }
        memset(st, 0,sizeof st);//判断当前点是否被用过
        //按照s0——>最小值——>最大值——>sn的顺序重构前缀和数组
        //使得相邻两项前缀和的差值a[i]最大
        int l=0,r=n;
        for(int i=s0;i>=0;i-=2)//所谓的隔一个一跳
        {
            a[l++]=s[i];
            st[i]=true;
        }
        for(int i=sn;i<=n;i+=2)
            {
                a[r--]=s[i];
                st[i]=true;
            }
        for(int i=0;i<=n;i++)
            if(!st[i]) a[l++]=s[i];
        LL res=0;
        for(int i=1;i<=n;i++)
            res=max(res,abs(a[i]-a[i-1]));
        printf("%lld\n",res);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值