自爆魂

博客园 首页 新随笔 联系 订阅 管理

http://acm.hdu.edu.cn/showproblem.php?pid=4923

给定一个序列a,元素由0,1组成,求一个序列b,元素在0~1之间,并且保证递增。输出最小的∑(ai−bi)2

对于每个由连续1开头,连续0结尾的段落有最优值x=a/a+b = sum/len (a为1的个数,b为0的个数),用栈维护各个段的x(d[i])值,如果当前x值小于前面一个段的x值,那么就要将两个段合并,相应调整sum和len.

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define clr0(x) memset(x,0,sizeof(x))

typedef long long LL;
int a[100005],s[100005],l[100005],r[100005],top;
double d[100005];
int main(){
    int n,_;
    RD(_);
    while(_--){
        top = 0;s[0] = 0;
        RD(n);
        for(int i = 1;i <= n;++i){
            RD(a[i]);s[i] = s[i-1]+a[i];
        }
        for(int i = 1;i <= n;){
            int j = i;
            d[++top] = a[i];
            while (j < n && a[j] >= a[j+1])
                d[top] += a[++j];
            l[top] = i;
            r[top] = j;
            d[top] /= (j-i+1);
            while (top > 1 && d[top] < d[top-1]){
                r[top - 1] = r[top];
                --top;
                d[top] = 1.0*(s[r[top]] - s[l[top]-1]) / (r[top]-l[top]+1);
            }
            i = j+1;
        }
        double ans = 0;
        for (int k=1;k<=top;++k)
            for (int i=l[k];i<=r[k];++i) ans += (d[k]-a[i])*(d[k]-a[i]);
        printf("%.6f\n",ans);
    }
    return 0;
}


posted on 2014-10-21 18:09  自爆魂  阅读(144)  评论(0编辑  收藏  举报