您的位置:首页 > 其它

hdu 4923 Room and Moor 2014多校第六场 贪心

2014-08-07 17:35 375 查看
题目链接:hdu 4923

给定A01串,求一个非递减B串使得(a[i]-b[i])^2的总和最小,求这个最小值

贪心策略

一个区间的置同一个数的最小情况:计一个区间的1个数以及0个数,分别用a,b表示,把数置为a/(a+b)可使得整体最小

因此,我们忽略起始的0,与末尾的1,从末尾开始每次找出1的比例最大的区间,去掉该区间之后重复该操作。即可保证b串非递减,且整体最优。
/*********************************************************************
FileName: 1003.cpp
Author: kojimai
Created Time: 2014年08月07日 星期四 13时06分29秒
*********************************************************************/
//一个区间内置同一个数的最优情况就是置为a/(a+b),a为1的数目,b为0的数目
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define FFF 100005
int a[FFF],n,cnt[50005][2];
int sum[50005][2];
int main()
{
int keng;
scanf("%d",&keng);
while(keng--)
{
memset(cnt,0,sizeof(cnt));
int n;
scanf("%d",&n);
double ans=0;
bool flag=true;//数0标志
int now=0;
double ze=0,on=0;
for(int i=1;i<=n;i++)//统计每一段的连续01的数量
{
scanf("%d",&a[i]);
if(a[i]==0)
{
if(flag)
{
cnt[now][0]++;
}
else
{
flag=true;
cnt[now][0]++;
}
if(now)
ze+=1;
}
else
{
if(flag)
{
now++;
flag=false;
cnt[now][1]++;
}
else
cnt[now][1]++;
on+=1;
}
}
if(cnt[now][0]==0)//去掉末尾的1
{
on-=cnt[now][1];
now--;
}
if(now==0)
{
printf("%.6f\n",0.0);
continue;
}
sum[now+1][0]=sum[now+1][1]=0;
for(int i=now;i>=1;i--)
{
sum[i][0]=sum[i+1][0]+cnt[i][0];
sum[i][1]=sum[i+1][1]+cnt[i][1];
}
while(now>=1)//每次找出整体比例最大的区间
{
int l=now,i=now;
double t=0;
while(i>=1)
{
double tt=(sum[i][1]-sum[now+1][1])*1.0/(sum[i][1]-sum[now+1][1]+sum[i][0]-sum[now+1][0]);
if(tt>t)
{
t=tt;
l=i;
}
i--;
}
//cout<<"l="<<l<<" now="<<now<<" t="<<t<<endl;
double cnt0=sum[l][0]-sum[now+1][0];
double cnt1=sum[l][1]-sum[now+1][1];
ans+=t*t*cnt0+(1-t)*(1-t)*cnt1;
now=l-1;
}
printf("%.6f\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: