B - 逆序对计数
解法:首先, 对于一个排列, 如果区间反转, 逆序数等于区间种所有的
对数减去当前的逆序对数, 即原本的正序对变为逆序对, 原本的逆
序对变为正序对。如果对于每个位置记录其到后面所有位置的逆
序对个数即可解决本题, 考虑从
[
l
,
r
]
→
[
l
,
r
+
1
]
[l, r] → [l, r + 1]
[l,r]→[l,r+1] 逆序对的个数增
加区间
[
l
,
r
]
[l, r]
[l,r] 中比
a
r
+
1
a_r+1
ar+1 的数的个数, 所以可以事前统计对于每一个
位置, 到他的前面的每一个位置比他大的数有多少个, 统计完直接
计算逆序对即可。
- 时间复杂度 O ( n 2 ) O(n^2) O(n2)
当然也可以使用树状数组统计逆序对, 可以很好的通过本题。
- 时间复杂度近似 O ( n 2 ) O(n^2) O(n2)
#include<cstdio>
#include<cstring>
const int N = 6010;
int a[N],tr[N],f[N][N],g[N][N];
int n;
inline int lowbit(int x)
{
return x&-x;
}
inline void add(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
tr[i]+=y;
}
inline int query(int x)
{
int res=0;
for(int i=x;i>0;i-=lowbit(i))
res+=tr[i];
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
f[i][j]=f[i][j-1]+query(n)-query(a[j]-1);
g[i][j]=g[i][j-1]+query(a[j]);
add(a[j],1);
}
memset(tr,0,sizeof tr);
}
int q;scanf("%d",&q);
while(q--)
{
int l,r;scanf("%d%d",&l,&r);
printf("%d\n",f[1][n]-f[l][r]+g[l][r]);
}
return 0;
}