• [BZOJ3289]Mato的文件管理


    题目大意

    给你(n)个数,(m)个询问

    每次询问一段区间([l,r]),可以进行交换相邻两个元素的操作,使这段区间从小到大排序的最小操作次数

    (n,mleq 50000),元素值在(1000000)内,没有重复元素

    解题思路

    这题第一感觉,好像和逆序对有关?

    那么给出性质:

    使区间[l,r]按题意方式从小到大排序的最小操作次数等价于区间[l,r]的逆序对总数

    这是一个很强的结论了

    尝试给出证明:

    首先证明操作次数的下限是逆序对个数

    很显然,每次操作(交换相邻两数)能且至多消除一个逆序对

    因此下限就是逆序对个数

    然后我们证明每次操作都可以消除一个逆序对

    同样很显然,假设不存在可以消除的逆序对,这意味着这个序列是有序的!

    同时,如果序列不是有序的,那么必定存在一对相邻的逆序对可以消除

    于是我们(类似贪心的)取到了最优方案

    维护

    于是这题就变成求区间逆序对个数了

    那么考虑用莫队和权值树状数组求解

    所谓权值树状数组,就是维护对应权值出现次数
    第i位上的值代表i的出现次数
    那么k的前缀和的含义就是不大于k的数一共有几个
    

    莫队最核心的就是得到指针移动对答案的影响

    我们考虑在末尾增加一个元素的情况:

    那个元素贡献的逆序对个数就是前面比它大的元素个数

    看样子需要两个权值树状数组,一个维护前缀和,一个后缀和?

    其实不用,因为比A大的元素个数就是总数-不大于A的元素个数

    这个可以直接用权值树状数组维护前缀和

    复杂度分析,(Blo=sqrt{n})最优

    复杂度(O(nsqrt{n}logn))

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    const int Base=230;
    int Blo[70000];
    
    int n,q;
    
    namespace tarr{
        int T[100000];
        void clear(){memset(T,0,sizeof(T));}
        inline int lowbit(int k){return k&-k;}
        void add(int K,int v){
            while (K<=n){
                T[K]+=v;
                K+=lowbit(K);
            }
        }
        int query(int K){
            int ret=0;
            while (K){
                ret+=T[K];
                K-=lowbit(K);
            }
            return ret;
        }
    }    
    
    struct query{
        int x,y;
        int id;
    }Q[100000];
    bool cmp_q(query X,query Y){return Blo[X.x]<Blo[Y.x]||(Blo[X.x]==Blo[Y.x]&&X.y<Y.y);}
    
    struct val{
        int V,id;
    }V[100000];
    bool cmp_v(val A,val B){return A.V<B.V;}
    
    int U[100000],valcnt;
    int L,R,val;
    int ans[100000];
    
    int main(){
        tarr::clear();
        for (int i=0;i<=50000/Base;i++)
            for (int j=1;j<=Base;j++)
                Blo[i*Base+j]=i;
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&V[i].V),V[i].id=i;
        std::sort(V+1,V+n+1,cmp_v);
        for (int i=1;i<=n;i++){
            if (V[i].V!=V[i-1].V) valcnt++;
            U[V[i].id]=valcnt;
        }
        scanf("%d",&q);
        for (int i=1;i<=q;i++) 
            scanf("%d%d",&Q[i].x,&Q[i].y),Q[i].id=i;
        std::sort(Q+1,Q+q+1,cmp_q);
        L=R=1;tarr::add(U[1],1);
        for (int i=1;i<=q;i++){
            while (R<Q[i].y){
                R++;
                val+=R-L-tarr::query(U[R]-1);
                tarr::add(U[R],1);
            }
            while (L>Q[i].x){
                L--;
                val+=tarr::query(U[L]-1);
                tarr::add(U[L],1);
            }
            while (R>Q[i].y){
                val-=R-L-tarr::query(U[R]-1);
                tarr::add(U[R],-1);
                R--;
            }
            while (L<Q[i].x){
                val-=tarr::query(U[L]-1);
                tarr::add(U[L],-1);
                L++;
            }
            ans[Q[i].id]=val;
        }
        for (int i=1;i<=q;i++) printf("%d
    ",ans[i]);
    }
    
  • 相关阅读:
    CaltrainTimes从设计到发布(基于Flex的手机应用)
    使用Flex构建Web和移动参考应用程序
    使用Flex4容器若干技巧
    移动设备外观设计的基础知识
    在移动设备应用程序中使用文本的指导原则
    在移动设备应用程序中使用软键盘
    多分辨率适配(下)
    多分辨率适配(上)
    CocosBuilder 多分辨率基础
    【2019-12-31】在逆境中锻炼自己的心态
  • 原文地址:https://www.cnblogs.com/ytxytx/p/9820960.html
Copyright © 2020-2023  润新知