bzoj3192 [JLOI2013]删除物品
3192: [JLOI2013]删除物品
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 668 Solved: 400
[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
Sample Output
6
HINT
1<=N1+N2<=100000
Source
【思路】
区间求和+单点修改。
十分巧妙地重组数据,例如将样例重组为541273,给定两个指针t1/t2,分别指向两堆的top,这样所谓的移动操作就变成了堆顶指针的滑动了。存在设1,单点修改,BIT求和即可。
注意ans为long long。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 6 using namespace std; 7 8 typedef long long LL; 9 const int maxn = 100000+10; 10 11 int read() { 12 char c=getchar(); 13 while(!isdigit(c)) c=getchar(); 14 int x=0; 15 while(isdigit(c)) { 16 x=x*10+c-'0'; 17 c=getchar(); 18 } 19 return x; 20 } 21 22 int a[maxn],rank[maxn],tmp[maxn]; 23 int n,m,t1,t2; 24 25 int cmp(const int& i,const int& j) { return a[i]>a[j]; 26 } 27 28 int c[maxn]; 29 int lowbit(int x) { return x&(-x); 30 } 31 void Add(int x,int d) { 32 while(x<=n) { 33 c[x]+=d; 34 x+=lowbit(x); 35 } 36 } 37 int Sum(int x) { 38 int res=0; 39 while(x>0) { 40 res+=c[x]; 41 x-=lowbit(x); 42 } 43 return res; 44 } 45 int main() { 46 n=read(),m=read(); 47 t1=n,t2=t1+1; 48 FOR(i,1,n) a[i]=read(); 49 FOR(i,n+1,n+m) a[i]=read(); 50 FOR(i,1,n) tmp[i]=a[n-i+1]; 51 FOR(i,1,n) a[i]=tmp[i]; 52 n += m; 53 FOR(i,1,n) rank[i]=i,Add(i,1); 54 55 sort(rank+1,rank+n+1,cmp); 56 57 LL ans=0; //long long型 58 FOR(i,1,n) { 59 int t=rank[i]; 60 if(t>=t2) { 61 ans+=Sum(t)-Sum(t2-1)-1; 62 Add(t,-1); 63 t2=t;t1=t2-1; 64 } 65 else { 66 ans+=Sum(t1)-Sum(t-1)-1; 67 Add(t,-1); 68 t1=t; t2=t1+1; 69 } 70 } 71 printf("%lld\n",ans); 72 return 0; 73 }
posted on 2015-11-20 18:28 hahalidaxin 阅读(267) 评论(0) 编辑 收藏 举报