[noi模拟赛]math (斜率优化,未测)

拖了许久的坑。。
sum[i]=t=1ia[t]
sum1[i]=t=1i1a[t]
sum2[i]=t=1isum[t]a[t]
f[i][k]前i个数,分成k部分的最小得分。
f[i][k]=min{f[j][k-1]+sum2[i]-sum2[j]-sum[j]*(sum1[i]-sum1[j]|k-1<=j< i)标准的2d/1d方程,进行斜率优化,设k1< k2,k1优于k2,则见代码。。还是维护下凸曲线。。然后这题精度有毒。也不知道能不能过。。。

#include <cstdio>
#include <cstring>
#define N 200010
#define ll long long
int n,k,a[N],p=0,q[N],h=0,t=1;
ll sum[N];
double sum1[N],sum2[N],f[2][N];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline double slope(int k1,int k2){
    return (f[p][k2]-f[p][k1]+sum2[k1]-sum2[k2]+sum[k2]*sum1[k2]-sum[k1]*sum1[k1])/(sum[k2]-sum[k1]);
}
int main(){
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    n=read();k=read();
    for(int i=1;i<=n;++i) a[i]=read(),sum[i]=sum[i-1]+a[i];
    for(int i=1;i<=n;++i){
        sum1[i]=sum1[i-1]+1.0/a[i];
        sum2[i]=sum2[i-1]+sum[i]*1.0/a[i];
    }
    for(int i=1;i<=n;++i) f[p][i]=sum2[i];
    for(int x=2;x<=k;++x){
        h=0,t=1;q[++h]=x-1;
        for(int i=x;i<=n;++i){
            while(h<t&&slope(q[h],q[h+1])<sum1[i]) ++h;
            f[p^1][i]=f[p][q[h]]+sum2[i]-sum2[q[h]]-sum[q[h]]*(sum1[i]-sum1[q[h]]);
            while(h<t&&slope(q[t],i)<slope(q[t-1],q[t])) --t;
            q[++t]=i;
        }p^=1;
    }
    printf("%.15lf\n",f[p][n]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值