洛谷
n个小鱼,n*(n+1)/2 个区间,也就是左右端点i,j都从1~n
左边的一只鱼的可爱值比右边的一只鱼可爱值更大,也就是区间中存在i<j,a[i] >a[j]就算一个答案数
排序+前缀和 +乘法原理
因为[l,mid] 和[mid+1,r]都是排好序的
因为 a[i] > a[j] ,所以[i,mid]中的数都是大于a[j]的
选择包含[i,mid]中的数作为左部分区间,右部分区间要包含j
左部分区间每次从[i,mid]区间选一个数下标为x,包含这个数的前面有 x-1+1个不同长度的包含x的区间,从i~mid总共有 i+(i+1) + (i+2) + ... +mid 个区间
右部分区间 有n-j+1 个包含下标j的不同长度的区间
#include <bits/stdc++.h>
#define x first
#define y second
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
typedef pair<int,int> PII;
typedef pair<char,int> PCI;
typedef long long LL;
typedef __int128 i128;
typedef unsigned long long ULL;
const int N=1e6+10 ;
const LL INF = 1e16;
int n;
PII a[N],b[N];
i128 ans;
inline void print(i128 x)
{
if(x < 0 )
{
putchar('-');x = -x;
}
if(x > 9) print(x/10);
putchar(x%10+'0');
}
void msort(int l,int r)
{
if(l == r ) return;
int mid = l+ r>>1;
msort(l,mid);msort(mid+1,r);
LL sum =0; // 左半边的位置的前缀和
for(int i=l;i<=mid;i++)
{
sum+=1ll * a[i].y;
}
int i=l,j=mid+1,k=1;
while(i<=mid && j <= r)
{
if(a[i].x <=a[j].x) // 升序
sum-=a[i].y,b[k++]=a[i++];
else // 否则包含[i,j]这段区间的区间都是答案
{
ans += sum * 1ll * (n-a[j].y+1);
// 因为[l,mid] 和[mid+1,r]都是排好序的
//
b[k++] = a[j ++ ];
}
}
while(i <= mid ) b[k ++ ] = a[i ++ ];
while(j <= r ) b[k ++ ] = a[j ++ ];
for(int i=l,j=1;i<=r;i ++,j++ )
a[i] = b[j];
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i].x, a[i].y = i;
msort(1,n);
print(ans);
}
int main()
{
ios
LL T=1;
// cin>>T;
while(T -- )
{
solve();
}
return 0;
}
树状数组
通常求逆序对我们是让树状数组上的值+1,现在我们实际上只要把+1改成
+(n−j+1) (i,j)
#include <bits/stdc++.h>
#define x first
#define y second
#define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
typedef pair<int,int> PII;
typedef pair<char,int> PCI;
typedef long long LL;
typedef __int128 i128;
typedef unsigned long long ULL;
const int N=1e6+10 ;
const LL INF = 1e16;
int n;
int a[N],b[N],c[N];
i128 ans,tr[N];
inline void print(i128 x)
{
if(x < 0 )
{
putchar('-');x = -x;
}
if(x > 9) print(x/10);
putchar(x%10+'0');
}
int lowbit(int x)
{
return x & -x ;
}
void add(int x,i128 c)
{
for(int i=x;i<=n;i+=lowbit(i))
tr[i] += c;
}
i128 query(LL x)
{
i128 res =0;
// x --;
for(int i=x;i;i-=lowbit(i)) res += tr[i];
return res;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int t;cin>>t;
a[i] = b[i] =t;
}
sort(b+1,b+1+n);
int tot=unique(b+1,b+n+1)-(b+1); //总共有多少个不同的数
// c[i] : a[i] 在排好序的位置
for(int i=1;i<=n;i ++ )
{
c[i]=lower_bound(b+1,b+tot+1,a[i]) -b;
}
for(int i=n;i>=1;i--)
{
LL l=i,r=n-i+1; // [r,l] ~ [l,r]
ans +=(i128)(l * query(c[i]));
add(c[i] + 1,r);
// c的下标从0开始 要+1
}
print(ans);
}
int main()
{
ios
LL T=1;
// cin>>T;
while(T -- )
{
solve();
}
return 0;
}