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(Xi−X)2=∑i=1n(kai−X)2∗k,
所以当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
(kai−X)2∗k−(k+1ai−X)2∗(k+1)=k(k+1)ai2−X2
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)}越大,方差减少的越多
X2不变,所以只要维护k(k+1)ai2的最大值就行了,因为k(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;
}