Gym-101775B-Scapegoat

Scapegoat
在这里插入图片描述
有n个问题,第i个问题复杂度是 a i a_i ai,m个Inkling,每个Inkling只能承担一个问题,但一个问题可以让多个Inkling承担,问Inkling承担问题复杂度的方差最小是多少。

我们可以先让每个问题都有一个Inkling承担,然后来分配剩下的m-n个Inkling,很容易想到用优先队列来维护最大值,麻烦的是维护什么的最大值,也就是排序函数怎么写。
因为方差公式 S 2 = ∑ i = 1 n ( X i − X ‾ ) 2 = ∑ i = 1 n ( a i k − X ‾ ) 2 ∗ k S^2=\sum_{i=1}^{n}{(X_i - \overline{X})^2}=\sum_{i=1}^{n}{(\frac{a_i}{k} - \overline{X})^2}*k S2=i=1n(XiX)2=i=1n(kaiX)2k,
所以当k增加1的时候,方差减小了 ( a i k − X ‾ ) 2 ∗ k − ( a i k + 1 − X ‾ ) 2 ∗ ( k + 1 ) = a i 2 k ( k + 1 ) − X ‾ 2 (\frac{a_i}{k}-\overline{X})^2*k-(\frac{a_i}{k+1}-\overline{X})^2*(k+1)=\frac{a_i^2}{k(k+1)}-\overline{X}^2 (kaiX)2k(k+1aiX)2(k+1)=k(k+1)ai2X2
X ‾ 2 不 变 , 所 以 只 要 维 护 a i 2 k ( k + 1 ) 的 最 大 值 就 行 了 , 因 为 a i 2 k ( k + 1 ) 越 大 , 方 差 减 少 的 越 多 \overline{X}^2不变,所以只要维护\frac{a_i^2}{k(k+1)}的最大值就行了,因为\frac{a_i^2}{k(k+1)}越大,方差减少的越多 X2k(k+1)ai2k(k+1)ai2

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <stack>
#include <assert.h>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (long long i= a; i <= b; i++)
#define reps(i, a, b) for (long long i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define l(node) tree[node].l
#define r(node) tree[node].r
#define val(node) tree[node].val
#define sum(node) tree[node].sum
#define lazy(node) tree[node].lazy
#define lazy1(node) tree[node].lazy1
#define lazy2(node) tree[node].lazy2
#define tr(node) tree[node]
//#pragma GCC optimize(2)
using namespace std;
const int N=1e6+7;
const int M=2e3+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
typedef long long ll;
#define Rep(i,a,b)for(ll i=a;i<=b;i++)
inline ll read()
{
    ll x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
double a[N];
struct Node
{
    int k;
    double num,a;
    bool operator<(const Node&t1)const{
        return a*a/(k*(k+1))<t1.a*t1.a/(t1.k*(t1.k+1));
    }
}b[N];
int main()
{
    int t=read(),Csae=0;
    while (t--){
        int n,m;
        double sum1=0;
        n=read();
        m=read();
        rep(i,1,n){
            scanf("%lf",&a[i]);
            sum1+=a[i];
        }
        sum1=sum1/m;
        priority_queue<Node>q;
        rep(i,1,n){
            b[i].num=a[i]-sum1;
            b[i].a=a[i];
            b[i].k=1;
            q.push(b[i]);
        }
        int x=m-n;
        while (x){
           Node e=q.top();
           q.pop();
           e.k++;
           e.num = (double) e.a  / e.k - sum1;
           x--;
           q.push(e);
        }
        double ans=0;
        while (!q.empty()){
            Node e=q.top();
            q.pop();
            ans+=e.num*e.num*e.k;
        }
        ans/=m;
        printf("Case #%d: %.12f\n",++Csae,ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值