HDU4923 Room and Moor

Room and Moor


Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 553 Accepted Submission(s): 156


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 input consists of multiple test cases. The number of test cases T(T<=100) occurs in the first line of input.

For each test case:
The first line contains a single integer N (1<=N<=100000), which denotes the length of A and B.
The second line consists of N integers, where the ith denotes Ai.


Output
Output the minimal f (A, B) when B is optimal and round it to 6 decimals.


Sample Input
4
9
1 1 1 1 1 0 0 1 1
9
1 1 0 0 1 1 1 1 1
4
0 0 1 1
4
0 1 1 1


Sample Output
1.428571
1.000000
0.000000
0.000000


Author
BUPT


Source
2014 Multi-University Training Contest 6

题意:求出一个非递减序列使它与A序列之差的平方和最小

首先要知道去掉前面的0和后面的1,只需要对剩下的序列进行处理就可以,把剩下的序列分成几组,每一组都是先有几个1然后几个0,如果序列是1 1 1 0 0 1 0,就分成两组,一组1 1 1 0 0,另一组1 0。

这样分好之后,YY一下,可以知道,每一组里取的最优值是num_1/(num_1+num_0)(rate),然后要将这些值非递减排列起来,用一个栈就好,如果当前值的rate大于栈顶的,直接入栈,否则将这个值出栈,与当前值合并,再判断与栈顶的rate的关系,这样就可以保证栈里都是非降序的了。

这题还有个小坑点(反正我被坑了)。。。。就是把后面的1全部去掉之后,结尾肯定是0,我们只赋值到了下标n-1,n后面的没有赋值也可能是0,所以统计0的个数就不对了。。代码也带了注释

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int MAXN=100010;
struct node
{
    int num0,num1,id;
    double ra;
}p[MAXN];
stack<node> S;
int a[MAXN];
int main()
{
    int t,n,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=0;i<n;i++)
            scanf("%d",&a[i]);
        int l=0,r=n-1;
        while(a[l]==0)
            l++;
        while(a[r]==1)
            r--;
        if(l>r)
        {
            printf("0.000000\n");
            continue;
        }
        int id=0;
        for(i=l;i<=r;)
        {
            int j=0,k=0;
            while(a[i]==1)
            {
                i++;
                j++;
            }
            while(a[i]==0&&i<n) //这里可能超出n。多统计了0
            {
                i++;
                k++;
            }
            p[id].id=id;
            p[id].num0=k;
            p[id].num1=j;
            p[id++].ra=1.0*j/(j+k);
        }
        for(i=0;i<id;i++)

        {
            if(S.empty())
                S.push(p[i]);
            else
            {
                node temp=S.top();
                if(temp.ra<=p[i].ra)
                {
                    S.push(p[i]);
                    continue;
                }
                node g=p[i];
                while(1)
                {
                    temp=S.top();
                    if(temp.ra>g.ra)
                    {
                        g.num0+=temp.num0;
                        g.num1+=temp.num1;
                        g.ra=1.0*g.num1/(g.num0+g.num1);
                        S.pop();
                    }
                    else
                    {
                        S.push(g);
                        break;
                    }
                    if(S.empty())
                    {
                        S.push(g);
                        break;
                    }
                }
            }
        }
        double ans=0;
        while(!S.empty())
        {
            node temp=S.top();
            S.pop();
            ans+=1.0*temp.num1*(1-temp.ra)*(1-temp.ra)+1.0*temp.num0*temp.ra*temp.ra;
        }
        printf("%.6f\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值