蓝桥杯2023年第十四届省赛真题-整数删除

蓝桥杯2023年第十四届省赛真题-整数删除_第1张图片

题目意思比较简单动态的去寻找最小值然后对其左右加上这个最小值,然后删除这个数接着对改变后的数组重新找到最小值然后改变 以此进行k次处理

1.这样不断找最小值我们不难想到优先队列

priority_queue,greater> q;

2.接着由于我们要再原来数组中删除一个数那么让数组继续接着,如果依旧保持使用数组的话时间复杂度是o(n)是我们明显不可以接受的,我们不难想到使用链表这样就可以再o(1)的时间内改变七左右的值,考虑左右端点则使用双向链表

for(int i=1;i<=n;i++)
    {
        cin>>v[i];
        l[i]=i-1,r[i]=i+1;
        q.push({v[i],i});// 原始的左右两端
    }

l[N],r[N]表示左右两端

开始删除数

void del(LL x)// 开始删除
{
    r[l[x]]=r[x],l[r[x]]=l[x];
    v[l[x]]+=v[x],v[r[x]]+=v[x];
}

3.结合

考虑到要一直去寻找最小值那么如果取出来的时候下标对应的值不和原来值一样表示已经收到影响变化了这个时候就需要把这个值改变之后加入

比如说

2 3 4 对应下标是1 2 3 

这样的话第一次取出来的答案是2 那么 对应下标是2 的需要加上2

那么这样第二次取出来是3 的时候和下标的值不对应需要重新把a[2],2 加入队列中(此时的实际第二小是a[3])则操作次数需要加回去

 while(k--)
    {
        auto t=q.top(); q.pop();
        auto [res,i]=t;// 表示第一个的值,表示坐标
        if (res!= v[i]) q.push({v[i], i}), k ++;// 如果坐标改变了
        else del(i);
    }

把以上结合就是此题的答案了

acwing选手也可以来支持一下蓝桥杯双链表加优先队列 - AcWing

#include 
using namespace std;
const int N=1e6+10;
typedef long long LL;
typedef pair PII;

LL r[N],l[N],v[N];
LL n,k;

void del(LL x)// 开始删除
{
    r[l[x]]=r[x],l[r[x]]=l[x];
    v[l[x]]+=v[x],v[r[x]]+=v[x];
}

int main ()
{
    priority_queue,greater> q;

    cin>>n>>k;
    r[0]=1,l[n+1]=n;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i];
        l[i]=i-1,r[i]=i+1;
        q.push({v[i],i});// 原始的左右两端
    }

    while(k--)
    {
        auto t=q.top(); q.pop();
        auto [res,i]=t;// 表示第一个的值,表示坐标
        if (res!= v[i]) q.push({v[i], i}), k ++;// 如果坐标改变了
        else del(i);
    }

    for(int i=r[0];i!=n+1;i=r[i])
    {
        cout<

后记: 对于这个题思考过后有了新的体会 我突然想到如果把这个加法改成减法会如何呢? 假设按照原来的思路的话那么后来被减的数的最小值会发生变化那么有点队列里面先取出来的不再是最小值那么如何处理呢?

很简单只要把后面改变的数加入队列中然后开一个st数组来记录一个数是否被删除就可以了这样我们就可得到更加全面的代码

// 但是对于这一题如果使用下面的代码用加法可能会超时,具体原因暂时还不太知道,希望能有读者指正

#include 
using namespace std;
const int N=5e5+10;
typedef long long LL;
typedef pair PII;

LL r[N],l[N],v[N];
LL n,k;
bool st[N];
priority_queue,greater> q;
void del(LL x)// 开始删除
{
    r[l[x]]=r[x],l[r[x]]=l[x];
    v[l[x]]-=v[x],v[r[x]]-=v[x];// 改成减法
    
    if(l[x]!=0)q.push({v[l[x]],l[x]});
    if(r[x]!=0)q.push({v[r[x]],r[x]});
}

int main ()
{
    
    
    cin>>n>>k;
    r[0]=1,l[n+1]=n;
    for(int i=1;i<=n;i++)
    {
        cin>>v[i];
        l[i]=i-1,r[i]=i+1;
        q.push({v[i],i});// 原始的左右两端
    }
    
    while(k--)
    {
        auto t=q.top(); q.pop();
        
        auto [res,i]=t;// 表示第一个的值,表示坐标
        if(st[i]) 
        {
            k++;
            continue;
        }
        st[i]=true;
        if (res!= v[i]) q.push({v[i], i}), k ++;// 如果坐标改变了
        else del(i);
    }
    
    for(int i=r[0];i!=n+1;i=r[i])
    {
        cout<

如有不足欢迎指正!

你可能感兴趣的:(蓝桥杯,蓝桥杯,c++,算法,数据结构,经验分享)