Problem - 238B - Codeforces

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} an1+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,an1+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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值