直接先吐槽一顿,明明对的,也不知道数据为什么就卡住了!!!我绝对是对的(我觉得QAQ)

题目链接

https://www.dotcpp.com/oj/problem2278.html

题目大意

n个人吃饭,共消耗s元。每人有ai元,问方差最小是多少。

解题思路

显然,公式中平方项里的平均值是不变的,给定s,给定n,那么平均值自然不变。变的是公式中的bi。
贪心啊,dp啥的都不行,直接贪心搞起来!
贪心思路:
我们要让公式里平方项的绝对值尽可能小,那就是让每个人花的钱尽可能一样,这样波动才小,这些花费的钱都应该尽可能靠***均值,
这样一来,就要分两种情况分析,要是某个人手中的钱数不到平均值,为了尽可能靠近平均值,他必须把钱全部交出来;要是某个人手中的钱数大于了平均值……
哎,卡住了,假如某人手中钱数大于平均值时,我们不能让他只花平均值的量啊,因为要是有钱不够的人没交到平均值的钱数,那所有人交的钱数肯定不到s,可见假如某人手中钱数大于平均值时,我们不能让他只花平均值的量,这样显然错误了,但是我们不要放弃这个思路,而是去变通一下。
你看我上面加粗的平均值其实并非 总钱数/总人数 这个固定的平均值。是什么呢?(动态平均值)
正确思路:
将手中钱数从小到大排序,若此人手中钱数 < (当前还需交的钱数/还没交钱的人数) ,没办法,他只能把手中的钱全部交上;若此人手中钱数 >= (当前还需交的钱数/还没交钱的人数) ,那这个人就交上 (当前还需交的钱数/还没交钱的人数) 这么多钱。
啥意思?
通俗点讲,为了让方差尽可能小,我们就得从排序后的钱中选出适当多的钱数,保证总选取钱数达到s的同时,让每个人花费的钱数波动尽可能小。
对于钱不够的人,我们就让他把钱都交上,因为这个人交的钱不够,所以后面有钱的就要为他买单,也就是他们得多出钱。又为了保证有钱人交钱波动也尽可能小,那每个有钱人就不仅仅要交s/n的钱数了,他们还得补上没钱人没交的那部分,波动最小的方式就是,他们平摊这些钱。
这样能明白了吗,看代码吧!会理解的更透彻的!

AC代码

被注释掉的代码可以暂时忽略。

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int a[N];
double s;
int n;
int main(){
    cin>>n>>s;
    /*
    for(int i=1;i<=n;i++){
        a[i]=rand();
    }
    for(int i=1;i<=n;i++){
        cout<<a[i]<<' ';
    }
    cout<<endl;
    */
    for(int i=1;i<=n;i++)
        cin>>a[i];

    sort(a+1,a+n+1);

    double avg=s/n;//(不变的)平均值 
    double rest=s;//剩下的人还得去平摊rest这么多钱
    double ans=0;

    for(int i=1;i<=n;i++){
        double now=rest/(n-i+1);//每次求剩下钱数的(变化的)平均值,算算剩下的人平摊,每个人要交多少钱
        if(a[i]<now) ans+=pow(a[i]-avg,2),rest-=a[i];//若此人钱数不到平均值,没钱人 
        else {ans+=pow(now-avg,2)*(n-i+1);break;}//只要找到有钱人了,后面都是有钱人,直接*就行了
        //else ans+=pow(now-avg,2),rest-=now;
    }
    printf("%.4lf",sqrt(ans/n));
}

注释解释

在核心代码部分,我注释掉了一段else语句,本质上和未被注释掉的else是相同的,只不过被注释掉的else将循环进行到底了,而未被注释的直接break出来了,小小区别,我的代码(被注释)只过了73,而未被注释的AC了!!!
我通过多组样例对比,依旧没发现错误,最上面最长的被注释掉的代码就是通过大数据看看差别,但,没找出来。
我只能强行解释为,循环到底,now多次进行除法,而因为计算机精度问题,会随着数据规模的变大而丢失的越多,最终量变导致质变,结果出现了问题。(这个解释是没有数据样例做支撑的,可以理解为半扯淡)

吐槽

打个训练赛就会签到题,心态直接爆炸,好不容易做到这个“难”题还会,还他妈卡在数据上了。
当时我死活不死心,老子就觉得老子的方法绝对没问题,果不其然,方法确实没问题,硬是被这个**数据卡住了,天理何在???QWQ
哎,就这样吧,勉强算是想出了个难题,还是能长点信心的,要不真受不了了!