P3253 [JLOI2013]删除物品
思路解析
主要难点就在于两个堆之间的变化。
当得出此题能够抽象化为
将数字输入顺序从 进行编号。得到一个序列,组成如下:
-
前 位由编号为 的数字逆序填。
-
第 位由数字编号为 的数字顺序填。
堆之间的变化实际上是堆顶的变化,只需要记录堆顶的位置,以及被取走的数,即可表示出两个堆的状态。
记 为第一个堆的堆顶所在的位置。每次更新时:
-
当取出的是第一个堆的数,堆顶即为这个数位置在左边的那个数, 即可。
-
取出的是第二个堆的数,堆顶也为这个数左边的数,即可。
对于答案 的计算:
-
当取出的是第一个堆的数,移走的数为第一堆堆顶到该数之间的数,即 。
-
当取出的是第二个堆的数,移走的数为第二堆堆顶到该数之间的数,此时第二堆的堆顶不能直接用 表示,因为不知道其下一个位置的数是否被取走,因此直接默认多算一个,再减去即可。。
code
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; struct A{ int pos,num; }a[100005]; int n1,n2,c[100005],top; long long ans; bool cmp(A x,A y){ return x.num>y.num;} void add(int x,int y){ for(;x<=n1+n2;x+=(x&-x)) c[x]+=y; } int sum(int x){ int k=0; for(;x;x-=(x&-x)) k+=c[x]; return k; } int main(){ scanf("%d%d",&n1,&n2); top=n1; for(int i=n1;i>=1;i--) scanf("%d",&a[i].num),a[i].pos=i,add(i,1); for(int i=n1+1;i<=n1+n2;i++) scanf("%d",&a[i].num),a[i].pos=i,add(i,1); sort(a+1,a+n2+n1+1,cmp); top=n1; for(int i=1;i<=n1+n2;i++){ if(a[i].pos<=top) ans+=sum(top)-sum(a[i].pos); else ans+=sum(a[i].pos)-sum(top)-1; top=a[i].pos-1; add(a[i].pos,-1); } cout<<ans<<endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!