本文最后更新于:3 years ago
题目链接:点击跳转
题意: 爱丽丝有一块蛋糕,她要把蛋糕切成n份,每一次操作,她会选择一块蛋糕(另大小为A),将其切成两半,两块大小分别为A / 2, (A + 1) / 2,及分成整数的两半,如果原大小为奇数,则一块会大1,现在给出一个序列,问有没有可能为一块蛋糕经过n - 1次操作后得到的
思路: 由每一块拼回去会因为有不同的拼接操作无法判断,可以逆向思维,模拟一块完整的蛋糕切成现在的大小序列,通过维护两个最大堆,如果模拟的堆顶小于该序列,说明无法切出这个序列,输出NO,如果等于,说明序列中的一个元素已经得到,将两个堆顶元素都弹出,如果大于,说明还需要切的更小,将切完的结果压回堆中,如果数组弹空了,说明可以切出该序列,输出YES.
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #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 ; }