Luogu P7870
P7870 兔已着陆 题解
出题人老东方了
蒟蒻第一次使用 \(\LaTeX\) ,用的不好还请谅解
前置芝士:栈(百度百科)
题意翻译:
有一初始为空的栈 \(S\) ,有两种操作:
1 l r
在栈顶依次加入元素 \(l,l+1,...r-1,r\)
2 k
将栈顶 \(k\) 个元素出栈,并询问它们的和
注意:\(1≤k≤10^{12}\),不开 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操作,将从 \(l\) 到 \(r\) 依次 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\),而是 \(r-n+1\)
同时取出后的原数列的后 \(n\) 项全部清除,因此取出后的 \(r\) 会变成 \(r-n\),则:
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;
}
此代码不能直接复制

浙公网安备 33010602011771号