zoukankan      html  css  js  c++  java
  • 【BZOJ1106】【POI2007】立方体大作战tet(贪心+树状数组/线段树优化区间和)

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

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 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

    样例输入1
    5
    5
    2
    3
    1
    4
    1
    4
    3
    5
    2
    样例输入2
    3
    1
    2
    3
    1
    2
    3

    Sample Output

    样例输出1
    2
    样例输出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
    ",ans);
        return 0;
    }
  • 相关阅读:
    课后作业 学号15100457
    开学第一课
    20180320作业2:进行代码复审训练
    20180320作业1:源代码管理工具调查
    软工作业PSP与单元测试训练
    构建之法 完成教材第一章P18第4题
    第一天上课 创建博客
    进行代码复审训练
    源代码管理工具调查
    软工作业PSP与单元测试训练
  • 原文地址:https://www.cnblogs.com/jian-song/p/11774057.html
Copyright © 2011-2022 走看看