思路: 求区间内逆序对个数,可以找出逆序对之后求它对整个区间的贡献。 例如 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;
}
京公网安备 11010502036488号