珂朵莉的数列

题目链接:https://ac.nowcoder.com/acm/problem/14522

思路: 求区间内逆序对个数,可以找出逆序对之后求它对整个区间的贡献。 例如 j,k是一个逆序对,那么它对整个区间的贡献应该是(j-0)*(n-k+1),因此,用树状数组枚举k,找出(1~k-1)范围内大于a[k]的数的坐标和就行了。

 

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stack>
#include <queue>
#include <cmath>
#define ll long long
#define pi 3.1415927
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
ll n,m;
ll a[1000005],b[1000005],c[1000005];
ll lowbit(ll i)
{
    return i&-i;
}
void add(ll i,ll p)  //这里是将坐标加上去,求前i项的坐标和
{
    while (i<=n)
    {
        c[i]+=p;
        i+=lowbit(i);
    }
}
ll getsum(ll k)
{
    ll res=0;
    while(k)
    {
        res+=c[k];
        k-=lowbit(k);
    }
    return res;
}
void Print(__int128_t x)  //__int128_t 输出方法
{
    if(x==0)
        return ;
    Print(x/10);
    putchar(x%10+'0');
}
int main ()
{
    ll T,i,t,j,k,p;
    cin>>n;
    for(i=1;i<=n;++i)
        scanf("%lld",&a[i]),b[i]=a[i];
    //先排序,之后二分,在a[i]中存的是第i个数的大小的位置
    sort(b+1,b+n+1);
    for(i=1;i<=n;++i)
        a[i]=lower_bound(b+1,b+n+1,a[i])-b;
    __int128_t sum=0;
    for(i=1;i<=n;++i)
    {
        sum+=(getsum(n)-getsum(a[i]))*(n-i+1);
        add(a[i],i);
    }
    if(sum==0)
        cout<<"0";
    else
        Print(sum);
    cout<<endl;
    return 0;
}

 

posted @ 2020-07-08 14:11  blowhail  阅读(204)  评论(0编辑  收藏  举报
Live2D