• HDU1394Minimum Inversion Number(树状数组)


    题目的意思一开始没有看清楚,题目的意思是:

           给你一段序列a1,a2,a3,a4,a5,a6,a7,,然后这段序列可以一直调动第一个数字到最后,例如:

    a2,a3,a4,a5,a6,a7,a1,…………直到循环了一遍。然后从这么多的序列中求出逆序列最小的一组。注意,序列中的数是从0开始计数的。一开始做还以为给的数字是随意给的呢,笑话,晕了好久。哈哈,切入正题,这道题还是树状数组,但是这道题有了别样的技巧,对于我这种小菜,算是吧。(大牛们做这个可能跟喝白开水一样,所以算不上技巧)。

          一开始,挺笨的,直接列举全部序列,然后就一段一段用树状数组求出各自的逆序列,哎,序列给的可是5000啊,列举全部,就是5000个不同的序列,然后每个再求其逆序列,肯定TLE啊。

         OK,说说收获吧,原来不用保存全部的序列,是有数学规律的,我一开始想不到,当然跟我没有理解好题意有很大关系。记住,上面说过序列里面的数是从0开始计数的,比如序列可能为0,4,2,1,6,3,5,然后它的逆序列为多少呢?小学生都会数啊,呵呵,当然是sum=0+0+1+2+0+2+1=6啦,那么另一个序列5,0,4,2,1,6,3,是多少?

         想想,5换到最前去了(为什么不将5从前往后换呢?因为从后面往前换,好算一点),接下来注意,,那么原来比5大的个数1,此刻就

    要用sum-1;因为5掉到最前,那么原来比5大的数,原来是逆序,现在恰好它变为正序了。那么原来比5小的个数5就变为逆序了,那么

    (sum-1)+5,,算算看对不对。此刻sum2=sum-1+5=6-1+5=10;

    刚刚好序列2的sum2=0+1+1+2+3+0+3=10;哈哈,数学真伟大。

    #include<iostream>
    #define lowbit(x) x&(-x)
    #define M 5001
    using namespace std;

    int flag[5001];
    int add(int n)
    {
        while(n<=M)
        {
            flag[n]++;
            n+=lowbit(n);
        }
        return 0;
    }

    int subsum(int n)
    {
        int sum=0;
        while(n>0)
        {
            sum+=flag[n];
            n-=lowbit(n);
        }
        return sum;
    }

    int main(void)
    {
        int number[5001],n;
        while(cin>>n)
        {
            int count=1,k=0,h=1,i,min=2100000000,sum,lmin,lmax;
            for( i=1;i<=n;i++)
                scanf("%d",&number[i]);
                sum=0;
                memset(flag,0,sizeof(flag));
                for(i=1;i<=n;i++)
                {       
                    //cout<<lmin<<endl;
                    lmax=i-1-subsum(number[i]+1);
                    add(number[i]+1);
                    sum+=lmax;
                    //cout<<lmax[i]<<"   "<<lmin[i]<<endl;
                }
            //    cout<<sum<<endl;
                for(i=n;i>1;i--)
                {                                    //注意在这道题中,每个number[i]都加上了1,因为树状数组处理的时候,不能处理0
                    sum+=number[i]-(n-(number[i]+1));//很神奇,找出规律,就是比number[i]+1大的数,前面比他大的个数为n-(number[i]+1),
                                                        //那么比它小的,当然就是number[i]+1-1啦,呵呵,又数数学规律
            //        cout<<sum<<endl;
                    if(min>sum)
                        min=sum;
                }
            //    cout<<sum<<endl;
           
                //cout<<max<<endl;
            cout<<min<<endl;
        }
        return 0;
    }

    改的很乱,哈哈,见谅!

  • 相关阅读:
    HDU 3389 Game (阶梯博弈)
    HDU1536&&POJ2960 S-Nim(SG函数博弈)
    HDU 2089 不要62(数位DP)
    ACdream 1210 Chinese Girls' Amusement(高精度)
    CodeForces 659D Bicycle Race (判断点是否为危险点)
    HDU 4549 (费马小定理+矩阵快速幂+二分快速幂)
    手动删除Win7系统服务列表中残留服务的操作步骤
    C++学习37 string字符串的访问和拼接
    C++学习36 string类和字符串
    C++学习35 模板中的函数式参数
  • 原文地址:https://www.cnblogs.com/cchun/p/2520068.html
Copyright © 2020-2023  润新知