【传送门:BZOJ1106】
简要题意:
有n种数,每种数有两个,给出一个2*n的序列,表示每个数在栈中的位置,可以任意交换相邻两个位置的数,若相邻两个数为同种数,则这两个数从栈中移除,然后所有上面的数都会掉落并形成连锁反应,求出移除所有数的最少步数
题解:
树状数组水题
若当前第i个位置出现的这个数是第一次出现,则将i位置+1,否则求出第一次出现的位置+1到第i个位置的数的个数(相当于将这个数消除所需的步数)
如何证明正确性:实际上是贪心,因为只有当出现1212这样的情况才会需要步数,不然就会在掉落的时候消除
参考代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; int a[110000],n; int lowbit(int x){return x&-x;} void change(int x,int d) { while(x<=2*n) { a[x]+=d; x+=lowbit(x); } } int getsum(int x) { int ans=0; while(x!=0) { ans+=a[x]; x-=lowbit(x); } return ans; } int pos[51000]; int main() { scanf("%d",&n); memset(pos,0,sizeof(pos)); memset(a,0,sizeof(a)); int ans=0; for(int i=1;i<=2*n;i++) { int x; scanf("%d",&x); if(pos[x]==0) { pos[x]=i; change(pos[x],1); } else { ans+=getsum(i)-getsum(pos[x]); change(pos[x],-1); } } printf("%d ",ans); return 0; }