洛谷地址:https://www.luogu.com.cn/problem/CF985C
题意:
你有一共m=n*k个木板。第i个木板的长度为ai。你必须用其中的每k条木板组成n个木桶。每条木板只能且必须属于一个木桶。我们把第j个木桶的最短的木板长度作为这个木桶的容积vj
你想要让这组合起来的n个木桶总容积最大。但是你需要让他们的容积尽量差不多,使得无论那两个木桶的容积差不超过l,即|vx-vy|<=l(1<=vx,vy<=n)。
输出这n个尽量相等的木桶的最大容积。如果无法组成满足要求的n个木桶,输出“0”
输入格式
第一行包括三个分开的整数n,k,l(1<=n,k<=10^5, 1<=n·k<=10^5, 0<=l<=10^9)
第二行包括m=n*k个整数,表示木板长度a1,a2,...,am ( 1<=ai<=10^9)
输出格式
输出一个整数,即n个满足要求的木桶的容积最大值
输入输出样例
4 2 1 2 2 1 2 3 2 2 3
7
2 1 0 10 10
20
1 2 1 5 2
2
3 2 1 1 2 3 4 5 6
0
说明/提示
In the first example you can form the following barrels: [1,2][1,2] , [2,2][2,2] , [2,3][2,3] , [2,3][2,3] .
In the second example you can form the following barrels: [10][10] , [10][10] .
In the third example you can form the following barrels: [2,5][2,5] .
In the fourth example difference between volumes of barrels in any partition is at least 22so it is impossible to make barrels equal enough.
解析:
注意,这个木板选择,是可以不连续的
首先对木板高度进行从小到大的排序
1:我们先考虑容积最小的情况:
n个木桶,对每个木桶的最短处,取a[1]~a[n],是最小的情况,此时最大差值为:a[n]-a[1],如果这个值>l,那么不管怎么组合,都是不能满足题意的。
那么直接输出0即可。
2:不管怎么组合,a1一定是某个木桶的容积,那么从这里入手,从前往后找到a[p]-a[1]<=l&&a[p+1]-a[1]>l
容积最大取到i=p处,p和末尾k-1个组合,即n*k-k+2到n*k,p-1处再和后第2*(k-1)个组合,依次类推。
如果p后的木板不够用了,就从i=1从前往后每隔k个取1个即可。
#include<cstdio> #include<stack> #include<map> #include<set> #include<queue> #include<cstring> #include<iostream> #include<algorithm> using namespace std; priority_queue<int,vector<int>,greater<int> > q;//优先为小的优先队列 typedef long long ll; const int maxn=1e5+20; ll a[maxn]; struct node { int x,id; }st[maxn]; bool cmp(node a , node b) { if(a.x==b.x) return a.id<b.id; return a.x<b.x; } int main() { // 4 0 20 ll n,k,l; cin>>n>>k>>l; for(int i=1;i<=n*k;i++) cin>>a[i]; sort(a+1,a+1+n*k); if(a[n]-a[1]>l) cout<<"0"<<endl; else { ll sum=0; int p=n*k; while(a[p]-a[1]>l) p--; int num=0; int md=p; for(int i=n*k;i-(k-1)>p;i-=(k-1)) { sum+=a[md--]; num++; } for(int i=1;i<=(p-num);i+=k) sum+=a[i]; cout<<sum<<endl; } }