标签:
题意:
给定一个长度为n的,由0和1组成的序列ai,求一个序列bi,使得∑(bi-ai)^2最小。其中0<=bi<=1,bi<=b(i+1),bi为浮点型。输出最小的∑(bi-ai)^2的值。
思路:显然开头为0的的部分和结尾为1的部分不用考虑
然后把其他序列划分成多个11111000形式的区域(这步也需要YY),每个区域分别求出bi(因地制宜的YY2333),求bi是二次函数的对称轴,如果bi不满足递增要求,比如bi-1>bi,所以如果不改变bi-1,bi至少要增大至bi-1才损失最小,一旦增大到bi-1又可以用二次函数模型,可以得到合并bi-1和bi的总区间再求bx会损失更小,万一合并后的bx也不满足递增关系那就继续合并综合判断还是比原来的损失小.
当然也有可能改变bi-1通过bi-1和bi-2合并的方式,这样YY下去最后会得到bi-2,bi-1,bi三个区间合并了,没必要损失bi-2,不可取这种方式来改变化bi-1
正确性已准确证明
// 2024 KB 1310 ms C++ 1370 B #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int inf= 0x3f3f3f3f; const int N =1e5+100; int a[N],num[N],len[N]; int main() { int T; scanf("%d",&T); while(T--) { int n,i; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); int st=1 , ed=n ; while(a[st]==0) st++; while(a[ed]==1) ed--; int l=0; double ans=0; while(st<=ed) { int cnt=0; for(i=st;i<=ed;i++) { if(i!=st&&a[i]>a[i-1]){ num[++l]=cnt; len[l]=i-st; st=i; break; } if(a[i]==1) cnt++; if(i==ed) { num[++l]=cnt; len[l]=i-st+1; st=i+1; break; } } while(l!=1&&(double)num[l]/len[l]<(double)num[l-1]/len[l-1]) { num[l-1]+=num[l]; len[l-1]+=len[l]; l--; } } for(i=1;i<=l;i++) { double val=(double)num[i]/len[i]; ans+=val*val*(len[i]-num[i])+(1-val)*(1-val)*num[i]; } printf("%.6f\n",ans); } return 0; }
HDU 4923 Room and Moor(数学+YY)(好题)
标签:
原文地址:http://blog.csdn.net/kalilili/article/details/44514167