CF1702F 题解
题目链接(CF,洛谷) | 强烈推荐博客中观看。
前言:本题解的解法参考了这个视频。
题意
多重集是一种特殊的集合,其元素可以重复,并且,和集合一样,元素的顺序不重要。如果两个多重集中,每个元素的出现次数都一样,那么这两个多重集就是相等的。
如,
现在给你两个多重集
在一次操作中,
- 替换
x 为2x - 替换
x 为\lfloor \frac{x}{2} \rfloor
注意你不能对多重集
请问你是否能使多重集
一些性质
这个
所以左移和乘二的运算是等价的,右移和向下取整的除二是等价的。
那么我们就可以发现一个性质,也就是集合(实为多重集,这里为了方便称为集合)
这里我来解释一下什么是后缀
现在有一个数,比如
而不重要的意思是:
如果我们设
这是因为可以通过左移和右移操作,在
这样就可以让
所以为了计算的方便,可以直接在输入的时候去掉元素的后缀
接下来,还有一个性质:
当且仅当
这里先解释一下,什么是二进制形式下的前缀。有两个数字,
那么从字符串的角度来看,
并且,显而易见的,如果
具体实现
有了这些性质,我们就可以搞出一些奇怪的方法了。
首先我们把集合
vector<int> a(n);
priority_queue<int> b;
for (int i = 0; i < n; i++) {
cin >> a[i];
while ((a[i] & 1) == 0) { // 如果最后一位是 0,那就一直右移来消除后缀 0
a[i] >>= 1;
}
}
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
while ((temp & 1) == 0) {
temp >>= 1;
}
b.push(temp);
}
然后再对
sort(a.begin(), a.end());
while (b.size()) {
int lb = b.top();
b.pop();
int la = a.back();
if (la > lb) {
goto FAIL;
} else if (la < lb) {
lb /= 2;
b.push(lb);
} else { // la == lb
a.pop_back();
}
}
可以看到,在这个 while 中,我们每次取出的
那么有三种情况。
对于第三种情况,如果说直接把
答案是不会的,因为
完整代码
#include <bits/stdc++.h>
using namespace std;
// author: tzyt
// ref: https://www.youtube.com/watch?v=HIiX3r5n27M
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n);
priority_queue<int> b;
for (int i = 0; i < n; i++) {
cin >> a[i];
while ((a[i] & 1) == 0) { // 如果最后一位是 0,那就一直右移来消除后缀 0
a[i] >>= 1;
}
}
for (int i = 0; i < n; i++) {
int temp;
cin >> temp;
while ((temp & 1) == 0) {
temp >>= 1;
}
b.push(temp);
}
sort(a.begin(), a.end());
while (b.size()) {
int lb = b.top();
b.pop();
int la = a.back();
if (la > lb) {
goto FAIL;
} else if (la < lb) {
lb /= 2;
b.push(lb);
} else { // la == lb
a.pop_back();
}
}
SUCC:
cout << "YES\n";
continue;
FAIL:
cout << "NO\n";
}
}
最后,希望这篇题解对你有帮助,如果有问题可以通过评论区或者私信联系我。