题目链接: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; }