I - Insurance(前缀和)

I - Insurancehttps://vjudge.csgrandeur.cn/problem/AtCoder-arc122_b

1.a[i]>2x,a[i]+x-min(2x,a[i])=a[i]-x;

2.a[i]<2x,a[i]+x-min(2x,a[i])=x;

这题如果x是一个定值,那这题是一个简单题,但x可以随便取。从一般来想,先把a排序,遍历每个ai值,x取a[i]/2(因为这样才知道2x和ai哪个小),a[i]左边的数取x,右边的数取a[i]-x,算出期望,然后遍历取个最小值。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 200000 + 10;

double a[N];
double sum[N];

int main()
{

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];//不用前缀和,直接暴力我觉得也行
    double ans = INF;
    for (int i = 1; i <= n; i++) {
        double x = a[i] / 2;
        double t = sum[n] - sum[i] - (n - i - i) * x;//x*i+(n-i)(a[i]-x)
                                                     //=(n-i)*a[i]-(n-i)*x+x*i
                                                     //=(n-i)*a[i]-(n-i-i)*x
        ans = min(ans, t / n);
    }
    printf("%.6lf\n", ans);
    return 0;
}

直接用结论(证明略),x取中间的a[i]/2,这样sum就有可能只等于a中间右边的元素的和,总和才有可能最小( 可以证明,无非就是x=a[0]/2或x=a[n]/2讨论)

#include <bits/stdc++.h>

using namespace std;
typedef long long int ll;
string s;

int main()
{
    double a[100010];
    double k;
    int i,n;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%lf",&a[i]);
    }
    sort(a+1,a+1+n);
    k=a[(n+1)/2];//取a数组中间的数
    double sum=0;
    for(i=1;i<=n;i++)
    {
        sum+=(double)k/2.00000000000+a[i]-min(a[i],k);
    }
    printf("%.16f",sum/n);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值