BZOJ1106: [POI2007]立方体大作战tet

【传送门: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\n",ans);
    return 0;
}

 

posted @ 2018-09-30 15:17  Star_Feel  阅读(162)  评论(0编辑  收藏  举报