[bzoj3192][JLOI2013]删除物品(树状数组)
3192: [JLOI2013]删除物品
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 872 Solved: 508
[Submit][Status][Discuss]
Description
箱子再分配问题需要解决如下问题:
(1)一共有N个物品,堆成M堆。
(2)所有物品都是一样的,但是它们有不同的优先级。
(3)你只能够移动某堆中位于顶端的物品。
(4)你可以把任意一堆中位于顶端的物品移动到其它某堆的顶端。若此物品是当前所有物品中优先级最高的,可以直接将之删除而不用移动。
(5)求出将所有物品删除所需的最小步数。删除操作不计入步数之中。
(6)只是一个比较难解决的问题,这里你只需要解决一个比较简单的版本:
不会有两个物品有着相同的优先级,且M=2
Input
第一行是包含两个整数N1,N2分别表示两堆物品的个数。
接下来有N1行整数按照从顶到底的顺序分别给出了第一堆物品中的优先级,数字越大,优先级越高。
再接下来的N2行按照同样的格式给出了第二堆物品的优先级。
Output
对于每个数据,请输出一个整数,即最小移动步数。
Sample Input
3 3
1
4
5
2
7
3
1
4
5
2
7
3
Sample Output
6
HINT
1<=N1+N2<=100000
Source
开始水博
接着上一个纪元讲的内容
这道题其实模拟就好,看题解前最好手动模拟一下
(快去模拟!)
那么在模拟时,容易想到的优化是把两个栈的栈顶接上,直接维护数列
维护时可以排序一遍,得出每个元素的顺序
比如对于5 4 1 2 7 3
排完序就是3 4 6 2 1 5
接下来维护一个01序列,表示第i位是否被弹出
那么答案就是按照排序后序列求01区间和(其实有好多细节哦)
取出一个数后置零即可
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<algorithm> 5 #define LL long long 6 using namespace std; 7 int rank[101000],num[101000]; 8 int bit[101000],n; 9 int lb(int x){ 10 return x&(-x); 11 } 12 int cmp(const int a,const int b){ 13 return num[a]>num[b]; 14 } 15 LL q(int x){ 16 LL ans=0; 17 while(x){ 18 ans+=bit[x]; 19 x-=lb(x); 20 } 21 return ans; 22 } 23 int c(int x,int v){ 24 while(x<=n){ 25 bit[x]+=v; 26 x+=lb(x); 27 } 28 return 0; 29 } 30 int main(){ 31 int a,b; 32 scanf("%d %d",&a,&b); 33 n=a+b; 34 for(int i=1;i<=n;i++)rank[i]=i; 35 rank[0]=a; 36 for(int i=a;i;--i)scanf("%d",&num[i]); 37 for(int i=1;i<=b;i++)scanf("%d",&num[i+a]); 38 sort(rank+1,rank+n+1,cmp); 39 for(int i=1;i<=n;i++)c(i,1); 40 LL ans=0; 41 for(int i=1;i<=n;i++){ 42 if(rank[i]>rank[i-1])ans+=q(rank[i]-1)-q(rank[i-1]); 43 else ans+=q(rank[i-1])-q(rank[i]);//????????????????rank????? 44 c(rank[i],-1); 45 } 46 printf("%lld\n",ans); 47 return 0; 48 }