ARC128C 简略题解

翻译自:Editorial - Daiwa Securities Co. Ltd. Programming Contest 2021(AtCoder Regular Contest 128) 有改动

不考虑 M 的限制:

  • 求出数组 A 后缀和 \(sum[i]\)

  • 求 m 为 sum[i]/i 最大的一个 i

  • 构造前 N-m 个系数为0,后面 m 个系数为 S/m

正确性:
调整法。设存在最优解 x ,使得 $x_i<x_{i+1} (0\leq i\leq N-1) $,除了 \(i=N-m\)。假设 x_0=0。令 d 为 x 的差分数组。对于每一个 i ,我将倒数 i 个数减去 d_i,最后 m 个数加上 \(d_i\times(N-i)/m\)。这样,我们抹平了 x_i 和 \(x_{i+1}\) 的差额的同时满足系数总额为 S。反复进行,可以达到上述情况。

考虑 M 的限制:

  • 如果 \(S/m\leq M\),那最优解就是让最后 m 个数系数为 S/m
  • 如果 \(S/m> M\),那最优解最后 m 个系数就是 M,问题转化为前 N-m 个数里面分配系数,使得系数单调,上界 M,总和为 \(S-m*M\)

O(n^2) 复杂度

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;

int a[N];
int n,m,s;

double solve(int l,int r,double s){
    double mx=0,suf=0; int pos=-1;
    for(int i=r;i>=l;--i){
        suf+=a[i];
        double tmp=suf/double(r-i+1);
        if(mx<tmp)mx=tmp,pos=i;
    }
    int len=r-pos+1;
    double tmp=s/double(len);
    if(tmp<=double(m))return tmp*mx*len;
    else return double(m)*mx*len+solve(l,r-len,s-m*len);
}

signed main(){
    cin>>n>>m>>s;
    for(int i=0;i<n;++i)
        cin>>a[i];
    double ans=solve(0,n-1,s);
    cout<<fixed<<setprecision(10)<<ans<<endl;
    return 0;
}
posted @ 2021-10-17 10:13  _Famiglistimo  阅读(110)  评论(1编辑  收藏  举报