思路
我们需要构造 \(W_1,W_2,\dots,W_N\),使得 \(\sum A_iW_i>\sum B_iW_i\)。
移项后等价于 \(\sum (A_i-B_i)W_i>0\)。
所以只需要考虑每一项的差 \(A_i-B_i\)。
如果存在某个位置满足 \(A_i>B_i\),那么这一项对答案有正贡献。
此时可以直接把这个位置的权值设得非常大,例如 \(10^{18}\),而其余位置全部设为 \(1\)。
这样正贡献会被放大到足以压过其他位置的负贡献。
因为对于任意位置都有 \(|A_i-B_i|\le 10^9\),并且 \(N\le 10^5\),所以其余所有位置造成的负贡献绝对值之和最多约为 \(10^{14}\)。
而只要存在一个 \(A_i>B_i\),把它的权值设为 \(10^{18}\),这一项至少可以产生 \(10^{18}\) 的正贡献,显然大于其他所有负贡献之和。
因此,只要存在 \(A_i>B_i\),就一定有解。
如果对于所有位置都有 \(A_i\le B_i\),那么对于任意正整数 \(W_i\) 都有 \((A_i-B_i)W_i\le 0\)。
所以 \(\sum (A_i-B_i)W_i\le0\),不可能严格大于 \(0\),因此无解。
于是结论非常简单:
- 如果存在 \(A_i>B_i\),输出
Yes; - 对这些满足 \(A_i>B_i\) 的位置令 \(W_i=10^{18}\);
- 其他位置令 \(W_i=1\);
- 如果不存在任何 \(A_i>B_i\),输出
No。
如何想到的
看到要求 \(\sum A_iW_i>\sum B_iW_i\) 以后,可以先移项成 \(\sum (A_i-B_i)W_i>0\)。
因为 \(W_i\) 是可以自由构造的,而且上界非常大,所以自然会想到:如果某一项的系数 \(A_i-B_i\) 是正数,就把这一项的权值尽量放大;如果系数不是正数,就让它的权值尽量小。
因此对于 \(A_i>B_i\) 的位置设成 \(10^{18}\),其余位置设成 \(1\)。
接下来只需要确认 \(10^{18}\) 是否足够大。其他所有位置的负贡献总和最多只有 \(10^5\times10^9=10^{14}\),而一个正位置就至少能贡献 \(10^{18}\),所以一定可以压过去。
这样就得到了这个非常直接的构造。
代码
#include <bits/stdc++.h>
#define rep(i,j,k) for (int i = (j); i <= (k); i ++)
#define per(i,j,k) for (int i = (j); i >= (k); i --)
#define uint unsigned int
#define ll long long
#define ull unsigned long long
#define db double
#define ldb long double
#define mkp make_pair
#define eb emplace_back
#define e_ emplace
#define ls (p << 1)
#define rs (p << 1 | 1)
//#define int ll
using namespace std;
const int N = 1e5 + 5;
//const int MOD = 998244353;
//const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LINF = 4e18;
//int T;
int n;
int a[N], b[N];
signed main () {
//freopen (".in", "r", stdin);
//freopen (".out", "w", stdout);
ios::sync_with_stdio (0);
cin.tie (0);
cin >> n;
bool x = false;
string ans;
rep (i, 1, n) cin >> a[i];
rep (i, 1, n) {
cin >> b[i];
if (a[i] > b[i]) {
ans += "1000000000000000000 ";
x = true;
}
else ans += "1 ";
}
if (x) cout << "Yes\n" << ans;
else cout << "No";
return 0;
}
复杂度
时间复杂度为 \(O(N)\)。
浙公网安备 33010602011771号