小苯的逆序对
题意:给定一个长度为n的排列,想知道排列中有多少个数满足
(
i
<
j
)
(i<j)
(i<j)且
(
a
i
>
a
j
)
(a_i > a_j)
(ai>aj)且
g
c
d
(
a
i
,
a
j
)
=
1
gcd(a_i,a_j)=1
gcd(ai,aj)=1的
(
i
,
j
)
(i,j)
(i,j)对。
注:一个长为n的排列即为在这个数组中,1~n每个数恰好出现一次
思路:首先题目翻译过来就是,问一个排列中有多少个逆序对的
g
c
d
gcd
gcd为1,求逆序对很好求,我们都知道可以用树状数组求,那么如何快速求出来一个数组中互质的个数呢?
我们令
d
p
d
dp_d
dpd为数组中
g
c
d
gcd
gcd为d的逆序对个数,那怎么快速求出来
d
p
d
dp_d
dpd呢?
我们可以将数组中是
d
d
d的倍数的所有数放到一个
v
e
c
t
o
r
vector
vector中,然后用树状数组求一遍逆序对的数量,例如,假设
d
=
10
d=10
d=10,我们可以把
10
,
20
,
50
,
100
10,20,50,100
10,20,50,100放到
v
e
c
t
o
r
vector
vector中,这些数都是
10
10
10的倍数,任意选择两个数,他们的
g
c
d
gcd
gcd一定是
10
10
10或者是
10
10
10的倍数,我们统计这些数中逆序对的个数,但是我们会发现一个问题,
50
,
100
50,100
50,100的
g
c
d
gcd
gcd并不是
10
10
10,而是
50
50
50,因此我们利用容斥原理还要减去
d
p
k
∗
d
(
k
∗
d
≤
n
)
dp_{k*d}(k*d \le n)
dpk∗d(k∗d≤n) 的个数,也就是减去
10
10
10的倍数
d
p
20
,
d
p
30
,
…
,
d
p
k
∗
10
dp_{20},dp_{30},\dots,dp_{k*10}
dp20,dp30,…,dpk∗10的个数,这样得到的就是
g
c
d
gcd
gcd为
10
10
10的逆序对个数,我们可以倒叙枚举
g
c
d
gcd
gcd,这样每求一个
d
d
d,它的
k
∗
d
k*d
k∗d都是计算过的,因此最后的答案就是
d
p
1
dp_1
dp1
还有一些细节就可以看代码了:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <cmath>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 10;
int n;
int tr[N],a[N];
int pos[N];
ll dp[N];
int lowbit(int x)
{
return x&-x;
}
void add(int x,int c)
{
for(int i=x;i<=n;i+=lowbit(i))tr[i]+=c;
}
ll sum(int x)
{
ll cnt=0;
for(int i=x;i>=1;i-=lowbit(i))cnt+=tr[i];
return cnt;
}
//上述为树状数组模板
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
pos[a[i]]=i;//记录下来a[i]在数组中的位置
}
for(int d=n;d>=1;d--)
{
vector<int>v;
for(int kd=d;kd<=n;kd+=d)v.push_back(pos[kd]);//vector存d的倍数在数组中的位置
sort(v.begin(),v.end());//将所有位置排序
for(int i=0;i<=v.size()+5;i++)tr[i]=0;
for(auto id:v)//用树状数组求逆序对的数量
{
//小技巧,因为每个数都是d的倍数,因此我们可以将每个数除d,这样得到的数就是1~v.size()
//清空数组就只用清空v.size()即可
dp[d]+=sum(v.size())-sum(a[id]/d);
add(a[id]/d,1);
}
for(int kd=2*d;kd<=n;kd+=d)dp[d]-=dp[kd];//容斥原理,减去d的倍数中的逆序对的数量
}
cout<<dp[1]<<"\n";
return 0;
}
···