【构造】CF1798 D

Problem - D - Codeforces

题意:

思路:

首先如果 a 全是 00,那么显然无解。

否则考虑从左到右构造新数列,维护新数列的前缀和 s。

  • 如果 s≥0,则在剩余未加入的数中随便选择一个非正数添加到新数列末尾。
  • 如果 s<0,则在剩余未加入的数中随便选择一个负数添加到新数列末尾。

因为保证了数列之和为 0,所以当 s≥0 时,你总能找到还没添加的非正数,同理第二种情况你也总能找到未添加的正数。

考虑这样构造的正确性:注意到 min ai​ ≤ s ≤ max ai​。这是因为每次总会添加一个和 s 异号的数。当 s≥0 时,能找到的最小数也是 min ai​,则新的前缀和 's′ 满足 s′≥s+min ai​​。类似可以证明s≤max ai​。

而任何区间的和都可以写成两个前缀和相减的形式。设 si​ 是长度为 i 的前缀和,则 ∣∑i=lr​ai​∣=∣sr​−sl​∣≤max ai​−min ai​。任何区间都满足这个限制,自然区间和绝对值的最大值也满足这个限制。正确性得证。

 

Code:

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 2e5 + 10;
constexpr int mod = 1e9 + 7;

void solve() {
    int n;
    std::cin >> n;
    
    std::vector<int> a(n);
    int ok = 0;
    for (int i = 0; i < n; i ++) {
        std::cin >> a[i];
        if (a[i] != 0) ok = 1;
    }

    if (!ok) {
        std::cout << "No" << "\n";
        return;
    }
    std::cout << "Yes" << "\n";

    int l = 0, r = n - 1;
    i64 s = 0;
    std::sort(a.begin(), a.end());

    std::vector<int> ans;
    while(l <= r) {
        if (s <= 0) {
            s += a[r];
            ans.push_back(a[r --]);
        }else {
            s += a[l];
            ans.push_back(a[l ++]);
        }
    }
    for (int i = 0; i < ans.size(); i ++) {
        std::cout << ans[i] << " \n" [i == ans.size() - 1];
    }
}
signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t = 1;
    std::cin >> t;
    while(t --) {
        solve();
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值