1.去掉前缀0和后缀1

2.将剩余的串划分成10串,每一位代表1或者0的个数

3.对于一个10节,b的值是一定的,假设1的数量为x,0的数量为y,那么可以求出一个函数f = x*(1-b)^2+y*b^2,化简后利用一元二次函数求最值的公式可知b取x/(x+y)时函数有最小值xy/(x+y)

4.用单调栈从左到右对每个10节进行遍历,每次比较当前10节的b值和栈顶10节的b值的大小,如果当前10节的b值大于栈顶10节的b值,那么直接将当前的10节入栈,否则弹栈直到当前10节的b值大于栈顶10节的b值,然后将当前的10节入栈。

5.将所有10节弹栈,每次根据公式xy/(x+y)累加结果

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <stack>
#include <cmath>
using namespace std;
typedef pair<int, int> P;
const int maxn = 1e5 + 10;
const double eps = 1e-8;
int dcmp(double x) {
if (fabs(x) > eps) return 0;
return fabs(x) > 0 ? 1 : -1;
}
int T, n, t[maxn], tot, num[maxn];
stack<P> s;

int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &t[i]);
tot = 0;
while (!s.empty()) s.pop();
int l = 1, r = n;
for (int i = 1; i <= n && t[i] == 0; i++) l++;
for (int i = n; i >= 1 && t[i] == 1; i--) r--;
if (l > r) {
printf("%.6lf\n", 0.0);
continue;
}
int cnt = 0;
while (l <= r) {
++tot;
cnt = 0;
while (l <= r && t[l] == 1) l++, cnt++;
num[tot] = cnt;
++tot;
cnt = 0;
while (l <= r && t[l] == 0) l++, cnt++;
num[tot] = cnt;
}
s.push(make_pair(num[1], num[2]));
for (int i = 3; i <= tot; i += 2) {
int x = s.top().first, y = s.top().second;
if (1.0*num[i]/(num[i]+num[i+1]) >= 1.0*x/(x+y)) s.push(make_pair(num[i], num[i+1]));
else {
int xx = num[i], yy = num[i+1];
while (1.0*xx/(xx+yy) < 1.0*x/(x+y)) {
xx += x, yy += y;
s.pop();
if (s.empty()) break;
x = s.top().first, y = s.top().second;
}
s.push(make_pair(xx, yy));
}
}
double ans = 0;
while (!s.empty()) {
int x = s.top().first, y = s.top().second;
s.pop();
ans += 1.0*x*y/(x+y);
}
printf("%.6lf\n", ans);
}
return 0;
}