蓝桥杯AcWing 题目题解 - 贪心

目录

 

AcWing 1055. 股票买卖 II

AcWing 1235. 付账问题

AcWing 1239. 乘积最大

AcWing 1247. 后缀表达式


 AcWing 1055. 股票买卖 II

给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

输入格式
第一行包含整数 N,表示数组长度。

第二行包含 N 个不大于 10000 的正整数,表示完整的数组。

输出格式
输出一个整数,表示最大利润。

数据范围
1≤N≤105

输入样例1:

6
7 1 5 3 6 4

输出样例1:

7

输入样例2:

5
1 2 3 4 5

输出样例2:

4

输入样例3:

5
7 6 4 3 1

输出样例3:

0

样例解释

样例1:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。共得利润 4+3 = 7。

样例2:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

样例3:在这种情况下, 不进行任何交易, 所以最大利润为 0。

思路:
按照样例一来分析:

在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。共得利润 4+3 = 7。

即我的收益等于我每次获取的股票的涨幅

#include<iostream>
using namespace std;
int n,sum;
int a[100010];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n-1;i++)
    {
        int d=a[i+1]-a[i];
        if(d>0)
        sum+=d;
    }
    cout<<sum<<endl;
    return 0;
}

AcWing 1235. 付账问题

几个人一起出去吃饭是常有的事。

但在结帐的时候,常常会出现一些争执。

现在有 n 个人出去吃饭,他们总共消费了 SS 元。

其中第 i 个人带了 ai 元。

幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?

为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。

这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是 1 分钱的整数倍。

你需要输出最小的标准差是多少。

标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的“偏差有多大”。

形式化地说,设第 i 个人付的钱为 bi 元,那么标准差为 :

输入格式

第一行包含两个整数 n、Sn、S;

第二行包含 n 个非负整数 a1, …, an。

输出格式

输出最小的标准差,四舍五入保留 4 位小数。

数据范围

1≤n≤5×105,
0≤ai,S≤109,

输入样例1:

5 2333
666 666 666 666 666

输出样例1:

0.0000

输入样例2:

10 30
2 1 4 7 4 8 3 6 4 7

输出样例2:

0.7928

 思路:

首先我们要知道标准差表示的是数据的波动程度,其值越大波动越大。要使得标准差小,我们就要尽可能使得数据都比较接近平均值。那么这题贪心策略应该是这样的:首先算出平均值s/ns/n,把数据从小到大排序,如果某个人的钱低于该值,那么他一定是将钱全部支付,然后其余不够的其他人平摊。但是,由于之前那个人钱不够,那么就会导致剩下人支付的平均值会增大,所以在这个平摊过程中很有可能存在某个人钱又低于这个平均值,又需要剩下的人平摊。如此反复,直到支付完成。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
int a[500010];
int main()
{
    double s;
    cin>>n>>s;
    for(int i=0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    
    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("%.4f",sqrt(res/n));
    return 0;
}

AcWing 1239. 乘积最大

输入样例1:

5 3
-100000
-10000
2
100000
10000

输出样例1:

999100009

输入样例2:

5 3
-100000
-100000
-2
-100000
-100000

输出样例2:

-999999829

分析:

k 如果是偶数的话,选出来的结果一定是非负数
             (1) # 负数的个数是偶数个的话,负负得正,那么一定是非负数
             (2) # 负数的个数如果是奇数个的话,那么我们就只选偶数个绝对值最大的负数or不选负数
k 如果是奇数个的话:
             (1)# 所有的数字如果都是负数,那么选出来的结果也一定都是负数    
             (2)# 否则的话,则一定至少有 1个非负数, 那么我们将最大的数取出来, 此时要选的个数是                          k--, k-- 是偶数,那么就又转化为是偶数的情况思考

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=1e5+10,mod=1000000009;

int n,k;
int a[N];
int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++) cin>>a[i];

    sort(a,a+n);    //核心
    
    int res=1;
    int l=0,r=n-1;
    int sign=1;
    if(k%2==1)  
    {
        res=a[r];   //如果是奇数,取最大值
        r--;
        k--;    //数目变成偶数,使之可用两边同时对比的操作
        if(res<0) sign=-1;  //得出全是负数且奇
    }
    while(k)
    {
        LL x=(LL)a[l]*a[l+1];   //如果是两负值,相乘得正可能最大
        LL y=(LL)a[r-1]*a[r]; 
        if(x*sign>y*sign)   //如果sign为-1,说明答案必然是负数,选出小的止损
        {
            res=x%mod*res%mod;  //x最大是 10^10,必须先mod,不然爆long long
            l+=2;
        }
        else
        {
            res=y%mod*res%mod;
            r-=2;
        }
        k-=2;
    }
    cout<<res;
    return 0;
}

AcWing 1247. 后缀表达式

给定 N 个加号、M 个减号以及 N+M+1 个整数 A1,A2,⋅⋅⋅,AN+M+1,小明想知道在所有由这 N 个加号、M 个减号以及 N+M+1 个整数凑出的合法的后缀表达式中,结果最大的是哪一个?

请你输出这个最大的结果。

例如使用 123+−,则 “23+1−” 这个后缀表达式结果是 4,是最大的。

输入格式
第一行包含两个整数 N 和 M。

第二行包含 N+M+1 个整数 A1,A2,⋅⋅⋅,AN+M+1。

输出格式
输出一个整数,代表答案。

数据范围
0≤N,M≤10E5,
−109≤Ai≤10E9

输入样例:

1 1
1 2 3

输出样例:

4

(网上找的大佬图解)

其实就是有n个加号,m个减号,n+m+1个数,可以加括号,问组成表达式的最大值

可以发现,现在如果我想加一个数的话,给它一个加号,放在括号外面,也可以给它一个减号,放在括号里面;减一个数同理。换句话说,只要用一个减号,一个最大值,一个最小值,其他数我想加就加,想减就减。那么为了使结果最大,我加上正数,减去负数,就是直接加上所有剩下数的绝对值,那么就解决了。//由上图式子b-(a-c-d-e)-->b-a+c+d+e,m>0就至少减一个数

其中,当m为0,也就是没有负数时,我们不需要实施反转操作,所有的操作都为+,此时我们只需增加所有的数字即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 200010;

int n, m;
int a[N];

int main()
{
    scanf("%d%d", &n, &m);
    int k = n + m + 1;
    for (int i = 0; i < k; i ++ ) scanf("%d", &a[i]);

    LL res = 0;
    if (!m)
    {
        for (int i = 0; i < k; i ++ ) res += a[i];
    }
    else
    {
        sort(a, a + k);  // 也可以不排序,找出最大值和最小值即可

        res = a[k - 1] - a[0];
        for (int i = 1; i < k - 1; i ++ ) res += abs(a[i]);
    }

    printf("%lld\n", res);

    return 0;
}

P1969 [NOIP2013 提高组] 积木大赛

 

 

这道题只要计算h[i]和h[i+1]两组的高度差即可:

  1. h[i]<h[i+1],即左边的一组比右边的矮,当高度满足左面时,右边的还差一些,那么ans加上两堆的高度差;
  2. h[i]>=h[i+1],即左边的一组比右边的高,当高度满足左面时,右边的也一定满足了,所以不需要增加ans。

 

#include <bits/stdc++.h>//热爱万能头
using namespace std;
int n,h[100050],ans;//ans为摆放次数
int main(){
	cin>>n;
	for(int i=1; i<=n; i++) cin>>h[i];
	for(int i=1; i<=n; i++) if(h[i]>h[i-1]) ans+=h[i]-h[i-1];//代码核心
	cout<<ans<<endl;
	return 0;
}

 

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NO.-LL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值