Acwing — 贪心题整理

一直以为自己的贪心还凑合,结果直接被干傻了


题目链接

解题思路:

  • 这个题一开始想的差不多,就是没敢敲,就是为了让他们支出的钱数与平均值的差值最小,首先我们可以求出平均数,然后排下序
  • 然后我们开始遍历,首先我们看第一位,如果他大于等于平均数,那么结果肯定为0(因为后面的都可以拿出平均数的钱)
  • 如果小于,那么让他拿出自己所有的钱,然后剩下的钱,让后面的人再平摊,也就是(s- ai)/ (n - 1), 然后我们每次res += (avg - bi) * (avg - bi)
  • 最后我们输出sqrt (res / n)

注意:

  • 不知道为什么最近有些题总是不敢敲,就怕错,可能比赛打少了,害怕去打比赛吧


代码:

#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1000010;

double a[N];

int main(){
    int n;
    double s;
    scanf("%d%lf",&n,&s);
    for (int i = 0 ; i < n; i ++){
        scanf("%lf",&a[i]);
        
    }
    sort(a, a + n);
    double avg = s / n;
    double num = avg;
    double res = 0;
    for (int i = 0; i < n ; i++){
        avg = s / (n - i);
        if (a[i] <= avg) {
            s -= a[i];
            res += (a[i] - num) * (a[i] - num);
        }
        else{
            s -= avg;
            res += (avg - num) * (avg - num);
        }
    }
    printf("%.4f\n",sqrt(res/n));
    return 0;
}


题目链接

解题思路:

  • 这道题也是考虑了一些情况,乘积最大,那么如果最后的结果是正数,那么我们让前面2个最大的正数相乘和后面的负数相比较,但是中间有很多情况
  • 所以我们分 k 的奇偶进行讨论,首先为偶数的话,那么我们之间判断前2个的乘积和后两个的乘积哪个大就OK。
  • 如果是奇数的话,那么同样道理,我们将他转变成偶数,所以我们首先要取一个值,这个值当然就是最大值(可以自己写一下),然后这里需要注意的是我们要判断最大值的正负,如果是正数,那么还是利用刚刚的偶数方法继续做,如果是负数,那么代表他的全部数都是负数,所以我们乘积的时候应该取较小的值进行相乘,这里的一个处理方法是让f(正负)符号变成负的,这样就不用改变判断条件了。

注意:

  • 这里我们要用x % mod * res , 如果用 res * mod * x,那么可能爆1e19了


代码:

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

using namespace std;

const int N = 100010;

const int mod  = 1000000009;

int a[N];

int main(){
    int n, k;
    scanf("%d%d",&n,&k);
    for (int i = 0; i < n; i ++){
        scanf("%d",&a[i]);
    }
    
    sort(a, a + n);
    
    int f = 1;
    
    int res = 1;
    
    int l = 0, r = n - 1;
    
    if (k % 2){
        res = a[n - 1];
        if (res < 0) f = -1;
        k --;
        r --;
    }
    
    while(k){
        long long x = (long long)a[l] * a[l + 1] ;
        long long y = (long long)a[r] * a[r - 1] ;
        if ( x * f > y * f){
            res = x % mod * res % mod;
            l += 2;
            k -= 2;
        }
        else{
            res = ((res % mod) * (y % mod)) % mod;
            r -= 2;
            k -= 2;
        }
    }
    printf("%d\n",res);
    return 0;
}



题目链接

解题思路:

  • 这题主要是理解好后缀表达式,他可以转换成很多种类型
  • 如果全是+那么很显然是全部加到一起
  • 如果存在一个减号,那么我们可以出现 1 到 n + m 个减号,因此我们让最大值减去最小值,其他的值全部都用abs即可


代码:

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

using namespace std;

const int N = 200010;

long long a[N];

int main(){
    int n, m;
    
    scanf("%d%d",&n,&m);
    
    int l = n + m + 1;
    
    for (int i = 0 ; i < l;i ++){
        scanf("%lld",&a[i]);
    }
    
    sort(a,a + l);
    
    if (!m){
        long long res = 0;
        for (int i = 0; i < l ; i ++){
            res += a[i];
        }
        printf("%lld\n",res);
    }
    else{
        long long res = a[l - 1] - a[0];
        for (int i = 1; i < l - 1 ; i ++){
            res += abs(a[i]);
        }
        printf("%lld\n",res);
    }

    return 0;
}

发布了121 篇原创文章 · 获赞 7 · 访问量 4336

猜你喜欢

转载自blog.csdn.net/LiangNiuMu/article/details/105449021