hdu 4923 Room and Moor (单调栈+思维)

题意:

给一个0和1组成的序列a,要构造一个同样长度的序列b。b要满足非严格单调,且

值为0到1的实数。最后使得  sum((ai-bi)^2)最小。

算法:

首先a序列开始的连续0和末尾的连续1是可以不考虑的。因为只要b序列对应开头为0、

末尾为1,既不影响单调性又能使对应的(ai-bi)^2=0。

然后,

先找111100、11100、10这样以1开始以0结束的序列块。每一块对应的b值相等且均为

这一块的平均值,即1的个数/0和1的总个数。

但是要满足b的单调性,则我们用栈来维护,如果后面一块的均值<前面一块的均值,则

合并这两块。也就是只要栈顶的块的均值小于要压入栈的块的均值,就一直合并,直到

满足单调性,再把当前的值压入栈。

最后只要一块块统计对应的sum((ai-bi)^2)就是答案了。

逗逼记忆---->比赛的时候我没有想到块,只想到除去前面的0和后面的1,中间的值都是一样,

用二分或者三分解决,只要控制精度=。=

P.S:   这题必须注意细节,否则极易丢失精度,主要是我代码注释的两个我开始没有控制好的地方。

o(╯□╰)o

#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 100010
using namespace std;

struct node
{
    double num,v; //v表示1的个数,num表示0和1的总个数
};
node stk[maxn];
double sum[maxn],a[maxn];

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            scanf("%lf",&a[i]);
            sum[i] = sum[i-1]+a[i];
        }
        int i = 1,k = n;
        while(a[i]==0) i++;
        while(a[k]==1) k--;
        int top = 0,le = i;
        node x,y;
        for(;i<=k;i++)
        {
            if(a[i]==0)
            {
                while(a[i]==0 && i<=k) //这里如果不加控制i<=k,i可能超出k
                    i++;
                double a = sum[i-1]-sum[le-1];
                double b = (double)i-le;
                while(top>0 && a/b<stk[top].v/stk[top].num) //这里也不能忘了top>0
                {
                    y = stk[top--];
                    a += y.v;
                    b += y.num;
                }
                x.v = a;
                x.num = b;
                stk[++top] = x;
                le = i;
            }
        }
        double ans = 0;
        while(top)
        {
            y = stk[top--];
            double val = y.v/y.num;
            ans += (1-val)*(1-val)*y.v + val*val*(y.num-y.v);
        }
        printf("%.6lf\n",ans);
    }
    return 0;
}

hdu 4923 Room and Moor (单调栈+思维)

时间: 2024-08-08 22:08:13

hdu 4923 Room and Moor (单调栈+思维)的相关文章

HDU 4923 Room and Moor(推理+栈维护)

HDU 4924 Room and Moor 题目链接 题意:给定一个01组成的a序列,要求一个b序列,b序列每个数值为[0, 1]之间的数,并且b序列为非递减序列,要求∑(ai?bi)2最小,求这个最小值 思路:推理,很容易看出,开头一段的0和末尾一段的1等于没有,然后中间每段类似111000这样1在前,0在后的序列,都可以列出一个公式,很容易推出选择的x为共同的一个值,为1的个数/(1的个数+0的个数)a,那么问题就变成要维护一个递增的x,利用一个栈去做维护,如果遇到一个位置递减了,那么就把

HDU 4923 Room and Moor【栈】【想法】

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4923 题目大意:给你一串A = {A1, A2,..., AN}由{0,1}组成, 你要构造出一字符串 B = {B1, B2,... , BN}与A的长度相同. 求出这个最小值. 最开始见到这个题目先是想了想应该怎么做,比如先把A串处理一下. 1)把A前面的0去掉 2)把A后面的1去掉 3)将每部分的特值算出来. 举个栗子吧,字符串A将前的0去掉,后面的1去掉之后,字符串可以简化为N个 {1..

HDU 4923 Room and Moor 贪心+栈

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4923 题意:,Bi可以是小数. 思路:很机智的想法,对于连续M个1+N个0的一块来说,最优解一定是,Bi=M/(M+N),因为Bi是递增的(可以手推),所以如果出现在后面的一块中的Bi>前面一块的Bi,那么就不可能取到最优解,所以将两块合并一起处理,这样过程中就需要用栈来维护了. 代码: #include <iostream> #include <cstdio> #include &

HDU 4923 Room and Moor (多校第六场C题) 单调栈

Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0 or 1. In order to beat him, programmer Moor has to construct another sequence B = {B1, B2,... , BN} of the same length, which satisfies that: Input The inp

HDU 4923 Room and Moor

Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0 or 1. In order to beat him, programmer Moor has to construct another sequence B = {B1, B2,... , BN} of the same length, which satisfies that: Input The inp

hdu 4923 Room and Moor(线性表)

题目链接:hdu 4923 Room and Moor 题目大意:给定一个序列a,元素由0,1组成,求一个序列b,元素在0~1之间,并且保证递增.输出最小的∑(ai?bi)2, 解题思路:首先剔除为首的0,和末尾的1,然后将中间部分成若干段由连续1开头,连续0结尾的各个段落.对于每一段有一个最优的值x=aa+b(a为1的个数,b为0的个数),用栈维护各个段的x值,如果当前x值小于前面一个段的x值,那么就要将两个段合并,a=ai?1+ai,b=bi?1+bi. #include <cstdio>

HDU 4923 Room and Moor(瞎搞题)

瞎搞题啊.找出1 1 0 0这种序列,然后存起来,这种情况下最好的选择是1的个数除以这段的总和.然后从前向后扫一遍,变扫边进行合并.每次合并,合并的是他的前驱.这样到最后从t-1找出的那条链就是最后满足条件的数的大小. Room and Moor Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 307    Accepted Su

hdu 4923 Room and Moor(数学题)2014多校训练第6场

Room and Moor                                                                          Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of

HDU 5875 H - Function 用单调栈水过了

单调栈,预处理to[i]表示第一个比a[i]小的数字,一直跳就可以. 这题是数据水而已. 这里学习下单调栈. 构造一个单调递增的栈,并且记录元素大小的同时记录它的id. 每次进来一个小的元素的话,就出栈,同时出栈的这个元素的to[id] = i了,因为这个元素是当时最大的.然后这个a[i]是第一个能让它出栈的,所以就是它了.后面的同理. #include <cstdio> #include <cstdlib> #include <cstring> #include &l