记录编号 |
242541 |
评测结果 |
AAAAAAAAAAAAAAAAAAAA |
题目名称 |
[国家集训队2011]刷题计划 |
最终得分 |
100 |
用户昵称 |
mikumikumi |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
0.644 s |
提交时间 |
2016-03-27 17:31:39 |
内存使用 |
1.27 MiB |
显示代码纯文本
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
const int SIZEN=50010,INF=0x7fffffff/2;
const double zero=1e-13;
int N,M;
double L;
double a[SIZEN];
double d[SIZEN];
double sqr(double x)
{
return x*x;
}
void read()
{
scanf("%d%d",&N,&M);
scanf("%lf",&L);
for(int i=1;i<=N;i++) scanf("%lf",&a[i]),d[i]=a[i]-a[i-1];
}
int piece[SIZEN];
double Calc_cost(double a,double y)//把a分成y个段的代价
{
double re=a*a/y-2.0*a*L+y*L*L;
return re;
}
int cut(double d,double x)//初中知识...
{
double t=sqr(d)/(sqr(L)-x);
if(t<=0) return 1;
//cout<<t<<endl;
double ans=(sqrt(4*t+1)-1)/2.0;
return max(ceil(ans),1.0);
}
int Calc_sum(double x)//把所有的区间的增量变成x的切割次数
{
int ans=0;
for(int i=2;i<=N;i++)
{
int tem=cut(d[i],x);
piece[i]=tem;
ans+=tem-1;
}
return ans;
}
double get()//
{
double ans=0;
for(int i=2;i<=N;i++) ans+=Calc_cost(d[i],piece[i]);
return ans;
}
void work()
{
double ma=-INF;
for(int i=2;i<=N;i++)
ma=max(d[i],ma);
//cout<<ma<<endl;
double l=sqr(L)-sqr(ma)*(0.5),r=0.0;
double ans=0;
if(l>=r)//不用加点已经是最优的
{
for(int i=2;i<=N;i++) piece[i]=1;
ans=get();
printf("%.3lf\n",ans);
return;
}
int tot=0;
while(++tot<=100)
{
double mid=(r+l)/2.0;
int tem=Calc_sum(mid);
if(tem>M) r=mid;
else l=mid;
}
Calc_sum(l);
//for(int i=1;i<=N;i++) cout<<piece[i]<<" ";
//cout<<endl;
ans=get();
printf("%.3lf\n",ans);
}
int main()
{
freopen("nt2011_seq.in","r",stdin);
freopen("nt2011_seq.out","w",stdout);
read();
work();
return 0;
}