Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round) C - Alice and the Cake(贪心+优先队列)
https://codeforces.com/contest/1654/problem/C
爱丽丝有一块蛋糕,她打算去切它。她将执行以下操作n-1次:选择一块重量w≥2的蛋糕(最初,蛋糕是一整块),并将其切成重量为⌊w/2⌋和⌈w/2⌉的两小块(⌊x⌋和⌈x⌉分别表示地板ceil和天花板floor功能)。
在将蛋糕切成n块后,她会将这n块蛋糕以任意顺序排列在桌子上。设ai为该行第i个蛋糕的重量。
给你一个数组a。确定是否存在一个初始权重和a一模一样的运算序列。
输出
对于每个测试用例,打印一行:如果数组a可能是Alice操作的结果,则打印YES,否则打印NO。
input
14
1
327
2
869 541
2
985214736 985214737
3
2 3 1
3
2 3 3
6
1 1 1 1 1 1
6
100 100 100 100 100 100
8
100 100 100 100 100 100 100 100
8
2 16 1 8 64 1 4 32
10
1 2 4 7 1 1 1 1 7 2
10
7 1 1 1 3 1 3 3 2 3
10
1 4 4 1 1 1 3 3 3 1
10
2 3 2 2 1 2 2 2 2 2
4
999999999 999999999 999999999 999999999
output
YES
NO
YES
YES
NO
YES
NO
YES
YES
YES
YES
NO
NO
YES
使用优先队列,每次对最大值进行比较,可以划分即继续往前划分,相等时则两端共同抛弃,不能时就及时退出(比如600中本来该遇到150时,但是却最大值只出现了100,那就及时退出)
要注意的是,正常能划分所有的数据的情况下,两个优先队列都是可以清除完整的
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=200200,M=2002;
const int mod=1e9+7;
int main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
LL T=1;
cin>>T;
while(T--)
{
LL n;
cin>>n;
LL sum=0;
priority_queue<LL> p;
for(LL i=1;i<=n;i++)
{
LL x;
cin>>x;
sum+=x;
p.push(x);//先把已知的所有数都排一个序
}
priority_queue<LL> q;
q.push(sum);//先把最大的放进去一步一步拆分
while(q.size()&&p.size())
{
LL u=q.top();//取出顶部的数字进行匹配
q.pop();
if(u<p.top()) break;//分不下去了,赶紧跳出来
if(u==p.top()) p.pop();//这个数字跟我拆出来的是一样的,可以删掉这个继续下一个
else if(u!=p.top()&&u>1)//大的离谱的时候,就需要拆分
{
q.push(u/2);
q.push((u+1)/2);
}
}
if(!q.size()&&!p.size()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}