Codeforces Round 892 (Div. 2)(VP)

A

       //b里放最小值,其他值放c。如果最大值=最小值,则无解。

void solve() {
    int n; cin >> n;
    vi a(n); liter(x, a) cin >> x; sort(all(a));
    if (a[0] == a[n - 1]){
        print(-1); return;
    }
    vi b, c;
    for (int i = 0; i < sz(a); ++i){
        if (a[i] == a[0]){
            b.pb(a[i]);
        }
        else{
            c.pb(a[i]);
        }
    }
    print(sz(b), sz(c));
    print(b);
    print(c);
}

B

//答案由每个数组中第二小值构成,对于每个数组,记录对答案的贡献值,并找出贡献最小的数组。贡献最小的数组用来存储其他数组的最小值。然后再将总的贡献值微改即可。

void solve() {
    int n; cin >> n;
    vvi a(n);
    ll sum = 0;
//min_val存储所有数组中第二小值里面最小的值。

    int min_val = 2e9, min_val_index = -1;
    int MM = 2e9;
    for (int i = 0; i < n; ++i){
        int m; cin >> m;
        a[i].assign(m + 2, 0);
        int minn = 2e9, secmin = 2e9;
        for (int j = 2; j <= m + 1; ++j){
            cin >> a[i][j];
            if (a[i][j] < minn){
                secmin = minn;
                minn = a[i][j];
            }
            else if (a[i][j] < secmin){
                secmin = a[i][j];
            }
        }
        a[i][0] = minn;
//如果当前数组长度为1,那么第二小值 == 最小值
        a[i][1] = m > 1? secmin : a[i][0];
        if (min_val > a[i][1]){
            min_val = a[i][1];
            min_val_index = i;
        }
        MM = min(MM, a[i][0]);
        sum += a[i][1];
    }
//以下操作等效于删除最小的第二小值,并把其他数组中的最小值移动到这个数组中,并加上其他数组所有值移动过来以后这个数组中的最小值。
    if (n > 1){
        sum = sum - a[min_val_index][1] + MM;
    }
    else sum = a[0][0];
    print(sum);
}

C

思路:要让n个数的*相应的排列的和在删除一个最大的值后的值最大,有这样的思路:

如果让i*j的和最大(1<=I, j <= n),那么就让每个i=j。然而题目要求删除一个最大的I * j,那么求解需要将要删除的I * j尽可能的变小,未删除的i*j尽可能变大,在这种大前提下找到一个最优解。假设要删除的数是n,那么让n*i尽可能的小,就要bf尝试各种下标i。同时,要保证其他的数尽可能的大,但是不能大过n*I,就将i后面的数从n-1逆序排列,升序i*逆序n – 1开始的排列,可能会满足最大的数尽可能小,而其他的数每个数都得到一定程度的变大。

测试:输入10

1 2 3 4 5 6 10 9 8 7

1 4 9 16 25 36 49 64 81 100 升序排列I = j各个位置的和,最后需要删除100,后4位是49+75+81=194

1 4 9 16 25 36 70 72 72 70      将n 放在I = 7的位置,最后需要删除72,后4位是70+72+70=212.

可以发现,对于这样的一个规则来说,可以找到一个下标起点,用来存放从n开始逆序排列的一个序列,会让这个序列*对应下标的值尽可能的接近,比如上面的70, 72, 72, 70,以至于删除一个最大的值后,其余的值加起来的和的贡献>升序排列删除最大值后的和的贡献。

 
void solve() {
    int n; cin >> n;
    ll sum = 0;
    auto cal = [&n](vi& a){
        ll result = 0;
        int in = 0;
        for (int i = 1; i <= n; ++i){
            result += 1ll * a[i] * i;
            if (a[in] * in < a[i] * i) in = i;
        }
        result -= a[in] * in;
        return result;
    };
    ll result = 0;
    vi a(n + 1);
    for (int i = 1; i <= n; ++i){
        a[i] = n;
        for (int j = 1; j < i; ++j) a[j] = j;
        for (int j = i + 1; j <= n; ++j) a[j] = a[j - 1] - 1;
        result = max(result, cal(a));
    }
    print(result);
}
 

总结:关键点在于尽快找到:将最大最尽可能的变小,其他的值尽可能变大的点->推理出从某个下标让n开始降序排列,然后暴力求解。

D

放个TLE代码

struct pts{
    int l, r, a, b;
    void read() {cin >> l >> r >> a >> b;}
    bl operator <(cst pts& x){
        return b < x.b;
    }
};
 
void solve() {
    int n; cin >> n;
    vector<pts> a (n);
    liter(x, a) x.read();
    sort(all(a));
    int q; cin >> q;
    while (q--){
        int pos; cin >> pos;
        liter(x, a){
            if (pos >= x.l && pos <= x.r) pos = max(pos, x.b);
        }
        print(pos, ' ');
    }
    newline;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值