题目链接:点击跳转
题意: 爱丽丝有一块蛋糕,她要把蛋糕切成n份,每一次操作,她会选择一块蛋糕(另大小为A),将其切成两半,两块大小分别为A / 2, (A + 1) / 2,及分成整数的两半,如果原大小为奇数,则一块会大1,现在给出一个序列,问有没有可能为一块蛋糕经过n - 1次操作后得到的
思路: 由每一块拼回去会因为有不同的拼接操作无法判断,可以逆向思维,模拟一块完整的蛋糕切成现在的大小序列,通过维护两个最大堆,如果模拟的堆顶小于该序列,说明无法切出这个序列,输出NO,如果等于,说明序列中的一个元素已经得到,将两个堆顶元素都弹出,如果大于,说明还需要切的更小,将切完的结果压回堆中。
代码如下:
#include<bits/stdc++.h>
#include <ostream>
using namespace std;
typedef long long ll;
#define endl '\n'
typedef pair<int, int> PII;
#define debug() cout.flush()
#define for0(i, a) for (ll i = 0; i < a; ++i)
#define REP(i, a, b) for (ll i = a; i < b; ++i)
#define RREP(i, a, b) for (int i = a; i >= b; --i)
const ll MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e5 + 5e2;
inline void init() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
inline void solve() {
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
priority_queue<ll> q, p;
ll tot = 0;
for0 (i, n) {
ll a;
cin >> a;
tot += a;
q.push(a);
}
bool f = true;
p.push(tot);
while (!q.empty()) {
ll qt = q.top();
q.pop();
ll pt = p.top();
p.pop();
if (qt != pt) {
if (qt > pt) {
f = false;
break;
} else {
q.push(qt);
p.push(pt >> 1);
p.push(pt + 1 >> 1);
}
}
}
cout << (f ? "YES" : "NO") << endl;
}
}
signed main() {
init();
solve();
return 0;
}