B3874 小杨的握手问题 题解
分析题意不难看出,如果所有人倒序进入教室,就变成了普通的逆序对问题。
直接归并排序或者树状数组求解即可。
解法一:归并排序
#include<iostream>
using namespace std;
const int N = 3e5+5;
int n;
int a[N], b[N];
long long ans = 0;
void merge(int l, int r)
{
int mid = l + r >> 1;
if(l>=r)
return;
merge(l, mid);
merge(mid+1, r);
int i = l, j = mid + 1, k = 0;
while(i<=mid && j<=r)
{
if(a[i]>a[j])
{
ans += mid - i + 1;
b[++k] = a[j++];
}
else
b[++k] = a[i++];
}
while(i<=mid)
b[++k] = a[i++];
while(j<=r)
b[++k] = a[j++];
for(int i=l;i<=r;i++)
a[i] = b[i-l+1];
}
int main()
{
cin>>n;
for(int i=n;i;i--) //倒序读入数据
cin>>a[i];
merge(1, n);
cout<<ans;
return 0;
}
解法二:树状数组
#include<iostream>
using namespace std;
const int N = 3e5+5;
int n;
int a, c[N];
long long ans;
int lowbit(int x)
{
return x & -x;
}
void add(int x, int y)
{
for(int i=x;i<=n;i+=lowbit(i))
c[i] += y;
}
int ask(int x)
{
int res = 0;
for(int i=x;i;i-=lowbit(i))
res += c[i];
return res;
}
int main()
{
cin>>n;
for(int i=n;i;i--)
{
cin>>a;
a++; //由于lowbit(0)=0,注意把a整体向右偏移一位
ans += ask(a-1);
add(a, 1);
}
cout<<ans;
return 0;
}