【BZOJ1106】【POI2007】立方体大作战tet(贪心+树状数组/线段树优化区间和)
作者:互联网
1106: [POI2007]立方体大作战tet
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1103 Solved: 802
[Submit][Status][Discuss]
Description
一个叫做立方体大作战的游戏风靡整个Byteotia。这个游戏的规则是相当复杂的,所以我们只介绍他的简单规
则:给定玩家一个有2n个元素的栈,元素一个叠一个地放置。这些元素拥有n个不同的编号,每个编号正好有两个
元素。玩家每次可以交换两个相邻的元素。如果在交换之后,两个相邻的元素编号相同,则将他们都从栈中移除,
所有在他们上面的元素都会掉落下来并且可以导致连锁反应。玩家的目标是用最少的步数将方块全部消除。
Input
第一行包含一个正整数n(1<=n<=50000)。接下来2n行每行一个数ai,从上到下描述整个栈,保证每个数出现且
仅只出现两次(1<=ai<=n)。初始时,没有两个相同元素相邻。并且保证所有数据都能在1000000步以内出解。
Output
第一行包含一个数m,表示最少的步数。
Sample Input
样例输入15
5
2
3
1
4
1
4
3
5
2
样例输入2
3
1
2
3
1
2
3
Sample Output
样例输出12
样例输出2
3
HINT
发现1:两个相同数之间最少要移动 出现次数为单数的数字的个数 次才能相消,于是想到贪心,sort两个数之间至少移动次数(即前述的个数),按这个顺序消。
发现2:不用sort,先消后消按什么顺序消并不影响,只要我们把最少移动次数=出现次数为单数的数字的个数,所以从左往右扫,树状数组维护一个区间和即可。
#include<iostream> #include<cstdio> #include<cstdlib> #include<ctime> #include<cctype> #include<algorithm> #include<cstring> #include<iomanip> #include<queue> #include<map> #include<set> #include<bitset> #include<vector> #include<stack> #include<cmath> #include<bits/stdc++.h> #define ri register int #define ll long long #define For(i,l,r) for(ri i=l;i<=r;i++) #define Dfor(i,r,l) for(ri i=r;i>=l;i--) using namespace std; const int M=5e4+5; int n,a[M<<1],l[M<<1],t[M<<1],ans; inline ll read(){ ll f=1,sum=0; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();} return f*sum; } inline int query(int x){ int sum=0; for(ri i=x;i;i-=i&(-i)){ sum+=t[i]; } return sum; } inline void add(int x,int val){ for(ri i=x;i<=n<<1;i+=i&(-i)){ t[i]+=val; } } int main(){ n=read(); For(i,1,n<<1) a[i]=read(); For(i,1,n<<1){ if(!l[a[i]]){ add(i,1);l[a[i]]=i; } else{ ans+=query(i)-query(l[a[i]]); add(l[a[i]],-1); } } printf("%d\n",ans); return 0; }
标签:int,POI2007,元素,样例,BZOJ1106,立方体,include,tet,define 来源: https://www.cnblogs.com/jian-song/p/11774057.html