Problem - 238B - Codeforces
题目大意:给定一个长度为n的序列,你可以将其分成两个子序列(子序列可以为空),给定一个h,定义函数 f ( a i , a j ) f(a_i, a_j) f(ai,aj), 如果 a i , a j a_i,a_j ai,aj在同一子序列, f ( a i , a j ) = a i + a j f(a_i, a_j)=a_i+a_j f(ai,aj)=ai+aj,否则 f ( a i , a j ) = a i + a j + h f(a_i, a_j)=a_i+a_j+h f(ai,aj)=ai+aj+h.现在让你给出构造方案,使得对于这两个子序列 m a x { f ( a i , a j ) } − m i n { f ( a i , a j ) } max\{f(a_i, a_j)\}-min\{f(a_i, a_j)\} max{f(ai,aj)}−min{f(ai,aj)}的值尽可能的小.
解题思路:想要使差值尽可能的小,那么就应该满足让最大值尽可能的小,最小值尽可能的大.先考虑基本情况:所有的数字都在一个序列中,此时最大值是 a n − 1 + a n a_{n-1}+a_{n} an−1+an,最小值是 a 1 + a 2 a_1+a_2 a1+a2,我们如果想要增大最小值,唯一的办法就是将 a 1 a_1 a1放在另一个序列里,这样最小值会变成 m i n ( a 1 + a 2 + h , a 2 + a 3 ) min(a_1+a_2+h, a_2+a_3) min(a1+a2+h,a2+a3),同时最大值也有可能会改变,最大值应该取 m a x ( a 1 + a n + h , a n − 1 + a n ) max(a_1+a_n+h, a_{n-1}+a_n) max(a1+an+h,an−1+an).我们只需要把这两种情况都判断一遍就可以了,还有就是需要特判n=2的情况,此时会越界.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define syncfalse ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N = 1e5+5;
ll n, h;
struct node{
ll val, id;
bool operator<(const node&a){
return val < a.val;
}
}a[N];
int main(){
syncfalse
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
cin>>n>>h;
if (n==2){
cout << "0\n2 2\n";
return 0;
}
for(int i = 1; i <= n; ++i){cin>>a[i].val;a[i].id=i;}
sort(a+1, a+1+n);
ll ans1 = (a[n].val+a[n-1].val)-(a[1].val+a[2].val);
ll mind = min(a[2].val+a[3].val, a[1].val+a[2].val+h);
ll maxd = max(a[1].val+h+a[n].val, a[n].val+a[n-1].val);
ll ans2 = maxd-mind;
if (ans1>ans2){
int tar = a[1].id;
cout << ans2 << "\n";
for (int i = 1; i <= n; ++i){
if (i==tar)cout << "1 ";
else cout << "2 ";
}
}else{
cout << ans1 << "\n";
for (int i = 1; i <= n; ++i){
cout << "2 ";
}
}
return 0;
}