[ABC190F] Shift and Inversions
题目
翻译
n
n
n个0
到 n-1
的全排列的数组,然后这个数组会循环左移n-1
, 求这个过程中数组的逆序数对是多少?
样例输入输出
输入
4
0 1 2 3
输出
0
3
4
3
样例解释
第一次,0,1,2,3
没有逆序对;
第二次,1,2,3,0
有
3
3
3个逆序对;
第三次,2,3,0,1
有
4
4
4个逆序对;
最后一次,3,0,1,2
有
3
3
3个逆序对。
思路
首先,把原数组的逆序对的个数求出来。运用树状数组。
后来,我们可以发现,当把数组的
a
i
a_i
ai移到最后去,发现逆序对的个数减少了
a
i
−
1
a_i -1
ai−1 个,增加了
n
−
a
i
n-a_i
n−ai 个。输出即可(
i
i
i
⇒
\Rightarrow
⇒最前面的)
代码
#include<iostream>
#include<queue>
#define lowbit(x) (x&(-x))
typedef long long ll;
using namespace std;
int c[2000006],a[1000005];
int n,m;
ll ans;
queue<ll> q;
void add(int x,int k){//单点修改
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=k;
}
}
int search(int begin,int end){//区间查询,这个题里用不到
int s=0;
for(int i=end;i;i-=lowbit(i)) s+=c[i];
for(int i=begin-1;i;i-=lowbit(i)) s-=c[i];
return s;
}
ll ask(int x){//输出1-x区间和
ll ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=c[i];
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]++;
q.push(a[i]);
}
ll cnt=0;
for(int i=n;i>=1;i--){
cnt+=ask(a[i]);
add(a[i],1);
}
cout<<cnt<<endl;
for(int i=1;i<n;i++){
ll d=q.front();
cnt-=d-1;
cnt+=n-d;
cout<<cnt<<endl;
q.pop();
}
return 0;
}
小白专场
什么是树状数组
顾名思义就是一个结构为树形结构的数组,于二叉树的结构类似但又不同,它是在二叉树的结构上删除了一些中间节点。
引入----lowbit是什么
l o w b i t ( x ) lowbit(x) lowbit(x) = x x x & \& & ( − x ) (-x) (−x)
换种说法就是这样
l
o
w
b
i
t
lowbit
lowbit
(
(
(
(
110
)
2
(110)_2
(110)2
)
)
)
=
=
=
(
10
)
2
(10)_2
(10)2
=
2
=2
=2
单点修改
void add(int x,int k){//单点修改 把c[k]加上k
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=k;
}
}
输出区间和
ll ask(int x){//输出1-x区间和
ll ans=0;
for(int i=x;i;i-=lowbit(i)) ans+=c[i];
return ans;
}
这个题就需要这两种类型
逆序对
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]++;
q.push(a[i]);
}
ll cnt=0;
for(int i=n;i>=1;i--){
cnt+=ask(a[i]);
add(a[i],1);
}
求过~~~