luogu 2503 & bzoj 2428
两个多星期没更新了,显然我摸了两个星期的鱼
但我已经悔改了,我觉得就算天大的事情也不能让我放弃刷题去打lol,letme!让帝!不!!!!
完蛋了啊。我写了个假的爬山又A了(
先随机一些数的位置,然后考虑拿出来一个数字丢到sum最小的那里面即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef double db; 4 const db eps = 1e-6; 5 const db delta = 0.90; 6 const db INF = 1e99; 7 int n,m;db a[22];db ave,ans = 1e18; 8 db sum[22];int pos[22]; 9 db pow2(db x){return pow(x,2);} 10 void sa(){ 11 memset(sum,0, sizeof(sum)); 12 db now=0,T=100; 13 for(int i=1;i<=n;i++)pos[i]=rand()%m+1,sum[pos[i]]+=a[i]; 14 for(int i=1;i<=m;i++)now+=pow2(sum[i]-ave); 15 while (T*delta>eps){ 16 int id1 = min_element(sum+1,sum+1+m)-sum; 17 int p = rand()%n+1,id2 = pos[p]; 18 if(id1==id2)continue; 19 db tmp = now; 20 now-=pow2(sum[id1]-ave)+pow2(sum[id2]-ave); 21 sum[id2]-=a[p];sum[id1]+=a[p]; 22 now+=pow2(sum[id1]-ave)+pow2(sum[id2]-ave); 23 if(now>tmp){// 24 sum[id2]+=a[p];sum[id1]-=a[p];now=tmp; 25 }else{ 26 pos[p]=id1; 27 } 28 T*=delta; 29 } 30 ans = min(ans, now); 31 } 32 33 int main(){ 34 scanf("%d%d",&n,&m); 35 for(int i=1;i<=n;i++){ 36 scanf("%lf",&a[i]); 37 ave+=a[i]; 38 } 39 ave/=m; 40 for(int i=1;i<=10000;i++) { 41 sa(); 42 } 43 printf("%.2f",sqrt(ans/m)); 44 }