题意:
给你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;
}