HDU 4923 Room and Moor

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4923

解题报告:给出一个长度为n的只包含0和1的序列,是否存在一个序列Bi满足一下条件:

1.           0 <= B[i] <= 1

2.          B[i] <= B[i+1]

3.          f(A,B) = ∑(i=1-n) (A[i] - B[i])^2 

4.          f(A,B)最小是多少 

前面的0可以直接去掉,后面的1可以直接去掉,然后剩下中间形如1 1 0 0的序列,在这样的区间中前后的B[i]很明显应该是相等才能保证最小的,

我们可以先分别求出每段这样的区间的B[i],然后维护一个单调队列,当要插入的B[i]大于等于队尾的B[i],则直接插入,当要插入的小于队尾的B[i],

则将队尾的那个区间跟现在要插入的区间合并然后求出一个新的B[i]代替,得到新的B[i]之后注意又要跟队尾比较。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<deque>
 6 using namespace std;
 7 #define maxn 100005
 8 struct node
 9 {
10     int a,b;
11     double x;
12 }B[maxn];
13 int A[maxn];
14 deque<node> que;
15 int main()
16 {
17     int T,n;
18     scanf("%d",&T);
19     while(T--)
20     {
21         scanf("%d",&n);
22         for(int i = 1;i <= n;++i)
23         scanf("%d",&A[i]);
24         while(n >= 1 && A[n] == 1)  //把后面的1去掉 
25         n--;
26         int s = 1;
27         while(s <= n && A[s] == 0)
28         s++;
29         if(s >= n)
30         {
31             printf("%.6lf
",0);
32             continue;
33         }
34         A[0] = 0;
35         int f = 0;
36         for(int i = s;i <= n;++i)
37         {
38             if(A[i] == 1)
39             {
40                 if(A[i-1] == 0 && A[i] == 1)
41                 {
42                     f++;
43                     B[f].a = B[f].b = 0; //初始化 
44                     
45                 }
46                 B[f].a++;
47             }
48             else B[f].b++;
49             
50         }
51         for(int i = 1;i <= f;++i)   //遍历一遍,计算出每节的x应该是多少 
52         B[i].x = (double)B[i].a / (double)(B[i].a + B[i].b);
53         
54     //    for(int i = 1;i <= f;++i)
55     //    printf("a = %d b = %d  x = %.6lf
",B[i].a,B[i].b,B[i].x);
56         que.clear();
57         node temp;
58         deque<node>::iterator iter;
59         for(int i = 1;i <= f;++i)        //维护一个单调队列 
60         {
61             if(que.empty() || B[i].x >= que.begin()->x)
62             que.push_front(B[i]);
63             else
64             {
65                 while(!que.empty() && B[i].x < que.begin()->x)
66                 {
67                     B[i].a += que.begin()->a;
68                     B[i].b += que.begin()->b;
69                     B[i].x = (double)B[i].a / (double)(B[i].a + B[i].b);
70                     que.pop_front();
71                 }
72                 i--;  //为了在下一次循环中,把这个节点插入到队列中 
73             }
74         }
75         double tot = 0;
76         for(iter = que.begin();iter != que.end();++iter)
77         tot += ((double)iter->a * (1.0 - iter->x) * (1.0 - iter->x) + (double)iter->b * iter->x * iter->x);
78         printf("%.6lf
",tot);
79     }
80     return 0;
81 }
View Code
原文地址:https://www.cnblogs.com/xiaxiaosheng/p/3904012.html