yuanshen77

导航

 

一.关于优先队列的题目


atcoder周赛题目

     总结本题利用用优先队列自动排序,首先我们需要明确的是先去更新小的,小的如果有更新不了的那么一定不会有人再和他融合了这样我们选择开一个大根堆greater,从小到大排列,然后我们开一个pair记录数值和出现次数,然后每次操作先判断他周围有没有数值相同的然后一起加起来,(首先必须大于等于2,这样才能融合)然后如果是偶数那么数值*2,出现次数/2;再放入优先队列中继续操作,如果是奇数的话每次都会剩下一个没有人与他融合,那么根据上面划线部分可知,他一定无法被融合,故我们设一个ans去记录这样的数,这就是最后的答案。

代码部分:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
#define ll long long
#define pii pair<ll,ll>
ll n,m;
int cnt[27];
int l[N],r[N];
priority_queue<pii,vector<pii>,greater<pii>>pp;
int main()
{
    ll n;
    cin>>n;
    ll a,b;
    for(int i = 1; i <= n ; i++)
    {
        cin>>a>>b;
        pp.push({a,b}); //前面数字 后面出现次数
    }
    ll ans = 0 ;
    while(pp.size())
    {
        //cout<<1;
       ll num = pp.top().first;
       ll cnt = pp.top().second;
        pp.pop();
        while(!pp.empty() && pp.top().first == num)
        {
            cnt+=pp.top().second;
            pp.pop();
        }
        if(cnt>=2)
        pp.push({num*2,cnt/2});
        if(cnt%2==1)
        {
            ans+=1;
        }
    }
    cout<<ans;

    return 0;
}

2.atcoder题目

总结:本体是一个构造题目,我们需要利用优先队列的自动排序性质去维护(大根堆),我们首先把0~9全部放进去,然后开始构造,目前只有0,无法构造,其余都可以往后面加比当前值还小的数。//以6,为例,我们可以在该数后面加比它小的数(0,1,2,3,4),然后都放入优先队列//,然后再用一个vector去存储答案,然后题目求最小的k个321样数,显然就是vector的最后一个数。

代码部分:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
#define ll long long
#define pii pair<ll,ll>
ll n,m;
int cnt[27];
int l[N],r[N];
priority_queue<ll,vector<ll>,greater<ll>>pp;
vector<ll>ans;
int main()
{
    cin>>n;
    for(ll i = 1 ; i <= 9 ; i++)
    {
        pp.push(i);
    }
    while(ans.size()<=n)
    {
        ll t = pp.top();
        pp.pop();
        ans.push_back(t);
        ll wei = t%10;
        for(ll i = 0 ; i < wei ; i++)
        {
            pp.push(t*10+i);
        }
    }
    cout<<ans[n-1];
    return 0;
}










二.关于set去维护的题目

1.牛客竞赛题目

总结:首先看到数组中没有出现的最小正整数数,要联想到用set去维护,思路是,把没有出现的数全部放到set中,当然放多大进去,得看数组长度,因为数组一共如果2e5的话,最坏情况就是出现的是数组里面是0~2e5-1,那么答案就是2e5,所以我们从0~2e5+1都判断一下,如果出现在数组里面,那我们就不去存set。(我们暂且不考虑什么奇数偶数,这样无非是开两个set去维护,我们讨论一下通常情况)再看操作1,是数组加入一个大于等于x的且没有出现在数组里面的数,我们先去用set的二分查询(lower_bound(x)第一个大于等于x的数,upper_bound(x)第一个小于等于x的数),然后将其删除出set因为他出现了 2.第二个操作就是直接输出set第一个数(奇数偶数讨论一下)

 

代码部分:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
#define ll long long
#define pii pair<int,int>
ll n,m;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    set<ll>pa,pb;  //pa偶数 ,pb奇数
    cin>>n>>m;
    for(int i = 0; i <= 1000000; i++)
    {
        if(i%2==0)
            pa.insert(i);
        else
            pb.insert(i);
    }
    int x;
    for(int i =1 ; i <= n ; i++)
    {
        cin>>x;
        if(x%2==0)
        {
            if(pa.find(x)!=pa.end()) {
                pa.erase(*pa.find(x));
            }
        }
        else
        {
            if(pb.find(x)!=pb.end()) {
                pb.erase(*pb.find(x));
            }
        }
    }
    ll op,mask;
    for(int i =1 ; i <= m; i++)
    {
        cin>>op;
        if(op==1)
        {
            cin>>x>>mask;
            if(mask==0) //  >=x   最小偶数
            {

                    pa.erase(*pa.lower_bound(x));
            }
            else
            {
                    pb.erase(*pb.lower_bound(x));
            }
        }
        else
        {
               cin>>mask;
               if(mask==0)
               {
                   cout<<*pa.begin()<<"\n";
               }
               else
               {
                   cout<<*pb.begin()<<"\n";
               }
        }
    }
    return 0;
}

2.atcoder

与上题同理

posted on 2023-12-09 21:26  江木匠  阅读(23)  评论(0)    收藏  举报