继续树状数组 1394

题目大意为:一个从a1到给顶一个an的数组,如果存在两个数(ai,aj)如果满足iaj,那么就称其为一个逆序数,可以一次把第一个数移到最后面,为一个新的序列,求给定一个序列,其所有情况的最小逆序数个数。
可以分别确定每一个序列的逆序数个数,一个序列的逆序数个数需要从每一个数都进行判断,判断当前的数(假设ai)后面的小于ai的数的个数,储存在ai中做参数,那么所有的a1到an的参数和即为该序列的逆序数个数。
可以假设有4个数:
3 2 1 4
首先代入4,S[4]==0,将0返回,并将C[4]记为1,代入1,S[1]==0,将0返回,C[1]记为1。代入2,前面的小于2的数只有1个,S[2]==1,将1返回,C[2]记为1。代入3,S[3]==2,将2返回,记C[3]为1。
可以总结:先将树状数组初始化为0,从右到左遍历,求得S[i]之和就是总的逆序数的和,遍历完以后自增1。
又是前n项求和的运算,便很自然地想到树状数组:

#include
#include
#include
#include
#include
using namespace std;
#define lowbit(x) (x&(-x))
#define MMAX 5005

int C[5005];

int sum(int i)
{
    int ans=0;
    while (i>0)
    {
        ans+=C[i];
        i-=lowbit(i);
    }
    return ans;
}

void add(int i,int k)
{
    while (i<=MMAX)
    {
        C[i]+=k;
        i+=lowbit(i);
    }
}

void main()
{
    int a[MMAX]={0};
    int i,j,k=0,n,m;
    scanf("%d",&n);
    m=n;
    for (i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (i=n;i>=1;i--)
    {
        k+=sum(a[i]);
        add(a[i],1);
    }
    printf("%d\n",k);
}

这只是一个序列的求解逆序数,那么当该序列发生了改变之后呢?
我们可以依次移动一个数据来得到一系列的数字值,记下最下的值,该值就是最终所求的解。
假设移动一个值,a[i],减去a[i]之后,ai后面有ai个比其小的数,ai放在最后其前面有n-1-ai个比其大的数,所以有k=k-a[i]+(n-1-a[i]);

#include
#include
#include
#include
#include
#include
using namespace std;
#define lowbit(x) (x&(-x))
#define MMAX 5010

int C[5010];

int sum(int i)
{
    int ans=0;
    while (i>0)
    {
        ans+=C[i];
        i-=lowbit(i);
    }
    return ans;
}

void add(int i,int k)
{
    while (i<=MMAX)
    {
        C[i]+=k;
        i+=lowbit(i);
    }
}

void main()
{
    int a[MMAX]={0};
    int i,j,k=0,n,m;
    while (scanf("%d",&n)!=EOF&&n!=0)
    {
        
        memset(C, 0, sizeof(C));
        memset(a,0,sizeof (a));
        k=0;
    m=n;
    for (i=0;i=0;i--)
    {
        k+=sum(a[i]+1);
        add(a[i]+1,1);
    }
    int ans=k;
    for(i=0;i

你可能感兴趣的:(继续树状数组 1394)