UVALive 6694

来源:互联网 发布:域名劫持查询 编辑:程序博客网 时间:2024/06/04 00:54

题意:

给你n件物品,每件物品都有重量Wi,分在三个箱子里,每个箱子至少一件物品。求总费用最少(每个箱子费用=箱子总重量*箱子内物品总数)。

思路:

先按升序排序,若把物品分成总量连续的两份,以对称轴位置为x轴,费用为y轴,画出图形是一个单峰函数。高效率求单峰函数最值可以想到三分,但题目要求分成三份,所以要有两个对称轴,这时可以枚举第一个对称轴,求第二个对称轴。时间复杂度O(nlogn)。这题区间是int型的,所以可以通过mid,mid+1,求斜率来三分,效率更快。

代码:

#include <bits/stdc++.h>using namespace std;typedef long long ll;const ll INFF = 0x3f3f3f3f3f3f3f3f;const int maxn = 2e4+7;ll arr[maxn],sum[maxn];int n;ll getSum(int l,int r){    return (ll)((sum[r]-sum[l])*(r-l));}ll trisearch(int x){    int l = x+1,r = n;    while(l<r-1)    {        int mid = (l+r)>>1;        int midd  = mid+1;        ll td = getSum(x,mid)+getSum(mid,n);        ll tdd = getSum(x,midd)+getSum(midd,n);        if(td<tdd)            r = mid;        else            l = midd;    }    return min(getSum(x,l)+getSum(l,n),getSum(x,r)+getSum(r,n));}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        for(int i = 1;i<=n;i++)            scanf("%lld",&arr[i]);        sort(arr+1,arr+n+1);        ll ans = INFF;        sum[0] = 0;        for(int i = 1;i<=n;i++)            sum[i] = sum[i-1]+arr[i];        for(int i = 1;i<=n-2;i++)            ans = min(ans,sum[i]*i+trisearch(i));        printf("%lld\n",ans);    }    return 0;}


原创粉丝点击