Codeforces Round #697 (Div. 3) A -D 解题报告
A. Odd Divisor
题意:
判断一个数是否存在 \(>1\) 的奇因数。
思路:
将一个数分解质因数显然可以发现除 \(2\) 都是奇数,那么我们只需要判断该数是不是 \(2\) 的整数次幂即可。
代码:
int main() {
int t; cin >> t;
while (t --) {
ll n; cin >> n;
while (n % 2 == 0) n >>= 1;
if (n == 1) puts("NO");
else puts("YES");
}
return 0;
}
B. New Year's Number
题意:
给定一个数 \(n\),问你能否构造如下等式:\(n = 2020 \times x + 2021 \times y\)。( \(x, y\) 均为大于等于零的整数)
思路:
将上述等式变换:\(n = 2020\times(x+y) + y\)。
那么显然 \(x + y = \frac{n}{2020}\),\(y = n \% 2020\)。
显然 \(y > x + y\) 时等式不成立。
代码:
int main() {
int t; cin >> t;
while (t --) {
int n; cin >> n;
int x = n / 2020;
int y = n % 2020;
if (y > x) puts("NO");
else puts("YES");
}
return 0;
}
C. Ball in Berland
题意:
给定男女的匹配关系,从中选出两对男女(没有重复的人),问有几种选法?
思路:
由于固定了只选择两对,那么我们可以枚举其中的一对关系 \(a\),而另一对中的人一定是 \(a\) 中没有出现过的,可以利用容斥原理,用 \(k\) - \(a\) 中出现过的人的关系数 + 1 即另一对可以选择的数量。(+1是因为会重复减一次)。
代码:
map<int, int> man, woman;
vector<int> v_man, v_woman;
int main() {
int t; cin >> t;
while (t --) {
man.clear();
woman.clear();
v_man.clear();
v_woman.clear();
int a, b, k;
cin >> a >> b >> k;
for (int i = 1; i <= k; i ++) {
int x; cin >> x;
v_man.pb(x);
man[x] ++;
}
for (int i = 1; i <= k; i ++) {
int x; cin >> x;
v_woman.pb(x);
woman[x] ++;
}
ll ans = 0;
for (int i = 0; i < k; i ++) {
int tmp_man = v_man[i];
int tmp_woman = v_woman[i];
ans += k - man[tmp_man] - woman[tmp_woman] + 1;
}
cout << ans / 2 << endl;
}
return 0;
}
D. Cleaning the Phone
题意:
有 \(n\) 个应用程序,第 \(i\) 个占用的内存为 \(a_i\),删除它的花费为 \(b_i\)。要求你至少腾出 \(m\) 的内存,问最少花费是多少?如果删光了所有应用都不行,就输出 -1
。
思路:
由于 \(b_i\) 的取值只有 \(1\) 和 \(2\)。那么我们就可以根据这个来分组,然后按内存从大到小排序,求一个前缀和,然后枚举某一组,用二分算出另一组。注意只选取某一组的特殊情况。
代码:
bool cmp(ll a, ll b) { return a > b; }
int main() {
int t; cin >> t;
while (t --) {
int n, m;
vector<ll> memory, v1, v2, sum1, sum2;
cin >> n >> m;
ll sum = 0;
for (int i = 1; i <= n; i ++) {
int x; cin >> x;
sum += x;
memory.pb(x);
}
for (int i = 1; i <= n; i ++) {
int x; cin >> x;
if (x == 1) {
v1.pb(memory[i - 1]);
} else {
v2.pb(memory[i - 1]);
}
}
if (sum < m) {
puts("-1");
continue;
}
sort(all(v1), cmp);
sort(all(v2), cmp);
int len_v1 = v1.size();
int len_v2 = v2.size();
ll pre = 0;
for (int i = 0; i < len_v1; i ++) {
sum1.pb(pre + v1[i]);
pre = sum1[i];
}
pre = 0;
for (int i = 0; i < len_v2; i ++) {
sum2.pb(pre + v2[i]);
pre = sum2[i];
}
int ans = INF;
int len_sum1 = sum1.size();
int len_sum2 = sum2.size();
// 全部选 2 的
int idx = lower_bound(all(sum2), m) - sum2.begin();
if (idx < len_sum2) ans = min(ans, (idx + 1) * 2);
for (int i = 0; i < len_sum1; i ++) {
ll tmp1 = sum1[i];
ll tmp2 = m - tmp1;
if (tmp2 <= 0) {
ans = min(ans, i + 1);
break;
} else {
int idx = lower_bound(all(sum2), tmp2) - sum2.begin();
if (idx < len_sum2) ans = min(ans, i + 1 + (idx + 1) * 2);
}
}
cout << ans << endl;
}
return 0;
}