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;
}
posted @ 2022-08-10 17:50  Vijurria  阅读(21)  评论(0编辑  收藏  举报