Luogu P7870

P7870 兔已着陆 题解

题目传送门

出题人老东方了

蒟蒻第一次使用 LATEX ,用的不好还请谅解

前置芝士:栈(百度百科)

题意翻译:

有一初始为空的栈 S ,有两种操作:

 1 l r

在栈顶依次加入元素 l,l+1,...r1,r

 2 k

将栈顶 k 个元素出栈,并询问它们的和

注意:1k1012,不开 long long 见祖宗

暴力思路(50分,开满会炸空间和时间):

手写一个基本的栈:

typedef long long ll;
struct STACK{
    ll stk[N],*_top=stk;//_top为栈顶指针
    
    void push(ll x){
        _top++;
        *_top=x;
    }
    void pop(){ 
        _top--; 
    }
    ll top(){
        return *_top;
    }
    bool empty(){
        return _top==stk;
    }
}stk;

empty()函数似乎没啥用

每次进行1操作,将从 lr 依次 push

每次2操作,令 ans=0,每次 ans+=stk.top(),stk.pop();
执行 k

思路简单,不多说了,最终结果:

优化(100分):

分析入栈元素特点,可以发现它们都是公差为1的等差数列

因此,可以用一个结构体代替一个等差数列:

typedef long long ll;
struct Stk{
    ll l,r;
    ll len(){//数列长度
        return r-l+1;
    }
}_stk[N];

则当要全部取出这个数列时,其贡献的价值:

ll getall(){ 
    return len()*(r+l)/2;//等差数列求和公式,O(1)得出贡献值
}

(Stk结构体成员函数)

但有时只会取出此数列的后 n 个(后入栈的先出栈),取出的这 n 个元素依旧是公差为1的等差数列,只是首项不再是 l,而是 rn+1

同时取出后的原数列的后 n 项全部清除,因此取出后的 r 会变成 rn,则:

ll get(ll n){
    ll res=n*(r+r-n+1)/2;//求和公式
    r-=n;
    return res;
}

(Stk结构体成员函数)

我们的栈结构体便可以如下:

struct STACK{
    struct Stk{
        ll l,r;
        ll len(){ return r-l+1; }
        ll getall(){ return len()*(r+l)/2;}
        ll get(ll n){
            ll res=n*(r+r-n+1)/2;
            r-=n;
            return res;
        }
    }_stk[N];
    Stk *_top=_stk;
    
    void push(ll l,ll r){
        _top++;
        *_top=(Stk){l,r};
    }
    bool empty(){ return _top==_stk; }
}stk;

empty()依旧没什么用

最后,每次访问栈顶的 k 个元素时,只需要分别看每个等差数列即可

k 大于等于栈顶数列的长度时,则将整个数列贡献值全部计入并出栈,并把 k 减去此数列的长度,直到 k 小于栈顶数列的长度

然后,取出此时栈顶数列的后 k 项:

ll get(ll k){
    ll res=0;
    while(k>=_top->len()){
        res+=_top->getall();
        k-=_top->len();
        _top--;
    }
    res+=_top->get(k);
    return res;
}

(STACK结构体成员函数)
完事了qwq

最终代码:

#include<bits/stdc++.h>
#define N 500005
typedef long long ll;
using namespace std;
struct STACK{
    struct Stk{
        ll l,r;
        ll len(){ return r-l+1; }
        ll getall(){ return len()*(r+l)/2;}
        ll get(ll n){
            ll res=n*(r+r-n+1)/2;
            r-=n;
            return res;
        }
    }_stk[N];
    Stk *_top=_stk;
    void push(ll l,ll r){
        _top++;
        *_top=(Stk){l,r};
    }
    ll get(ll k){
        ll res=0;
        while(k>=_top->len()){
            res+=_top->getall();
            k-=_top->len();
            _top--;
        }
        res+=_top->get(k);
        return res;
    }
    bool empty(){ return _top==_stk; }
}stk;
int main(){
    ll n;
    cin>>n;
    while(n--){
        int op;
        scanf("%d",&op);
        if(op==1){
            ll l,r;
            scanf("%d%d",&l,&r);
            stk.push(l,r);
        }
        else{
            ll k;
            scanf("%d",&k);
            printf("%lld\n",stk.get(k));
        }
    }
    return 0;
}

此代码不能直接复制

posted @   untitled0  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示