20241031模拟赛总结

T1 可以了

题目描述

科技

数学

分析

此题一眼顶针鉴定为和平均数的性质有关。
我们发现,对于这个array的一个区间,如果他的平均值大于整个数组的平均值,那么另一部分的平均值一定小于整个数组的平均值。
由此,不难想到:
我们将数组中每个数先减去平均数,然后维护一个前缀和。
那么任一区间的的平均值可表示为 s u m j − s u m i − 1 j − i + 1 + a r v \frac{sum_j - sum_{i - 1}}{j - i + 1} + arv ji+1sumjsumi1+arv
此时问题转化为:问怎么选 s u m I sum_I sumI,使得任一的j均可使 s u m j − s u m i − 1 j − i + 1 > = 0 \frac{sum_j - sum_{i - 1}}{j - i + 1} >= 0 ji+1sumjsumi1>=0
答案显然:选择最小的 s u m i sum_i sumi
这样,此题便愉快的做完了。
TIPS:为了让浮点不出精度问题,我们将所有数扩大n倍,避开double

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 500005;
/*
it is obveriously that if the the numbers which Alice choose is larger than the average of the whole array,she must be win.
so we use average number to minus every number in the array.
the question then turn into : find the smallest index whose all the field start from it is bigger than 0.
It can be solved by using prefix and.
we can just find the minual of tham as j - 1,if then field if[j,i].
*/
int n,ans;
long long sum[N],s,a[N];
int main()
{
    scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        scanf("%lld",&a[i]);
        s += a[i];
    }
    for(int i = 1;i <= n;i++)
        a[i] = a[i] * n - s;
    for(int i = 1;i < n;i++) {
        sum[i] = sum[i-1] + a[i];
        ans = (sum[i] < sum[ans] ? i : ans);
    }
    printf("%d\n",ans + 1);
    return 0;
}

T2 淘汰

题目描述

科技

反悔贪心

分析

此题为最优规划类问题,考虑贪心/DP。
此题需要用到反悔贪心。
其实一个显然的思路是:有券先用券,没有券考虑两种情况:

  1. a较小,直接加。
  2. a较大,把一个用券的变成不用的,然后用券。

所以,此题我们用3个堆,分别维护最小的未加入的a,最小的未加入的b,最小的已加入的b转a所需的代价。

直接转移即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 500005;
long long n,k,t,ans;
struct programdata{
    long long a,b;
    bool operator < (const programdata tmp) const {
        return b < tmp.b;
    }
}p[N];
//反悔贪心的反悔堆
priority_queue<pair<long long,long long>,vector<pair<long long,long long> >,greater<pair<long long,long long> > >q1,q2,q3;
bool vis[N];
int main()
{
    scanf("%lld%lld%lld",&n,&k,&t);
    for(int i = 1;i <= n;i++)
        scanf("%lld%lld",&p[i].a,&p[i].b);
    sort(p + 1,p + 1 + n);
    for(int i = 1;i <= k && t >= 0;i++) {
        t -= p[i].b;
        vis[i] = 1;
        ans++;
    }
    if(t < 0) {
        printf("%lld\n",ans - 1);
        return 0;
    }
    for(int i = 1;i <= n;i++) {
        if(vis[i]) {
            q3.push(make_pair(p[i].a - p[i].b,i));
        } else {
            q1.push(make_pair(p[i].a,i));
            q2.push(make_pair(p[i].b,i));
        }
    }
    while(t > 0) {//现在试图加入其他的点
        while(vis[q1.top().second])
            q1.pop();
        while(vis[q2.top().second])
            q2.pop();
        long long o1 = q1.top().second,o2 = q2.top().second;
        long long x = q1.top().first,y = q2.top().first,z = q3.top().first;
        ans++;
        if(x < y + z) {//情况1:直接用a更优
            q1.pop();
            t -= x;
            vis[o1] = 1;
        } else {//情况二:用b再调整出一个b用a更优
            q2.pop();
            q3.pop();
            q3.push(make_pair(p[o2].a - p[o2].b,o2));
            t -= y + z;
            vis[o2] = 1;
        }
    }
    if(t < 0)
        ans--;
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值