该题数据已经被加强,而且出现hack数据,洛谷的部分用树状数组的题解可能有误,因此我这个新手蒟蒻想写一篇新的题解。
题目详情:
https://www.luogu.com.cn/problem/P1908
不知道树状数组的童鞋请先移步。。。。(有关树状数组已经有苣佬讲的很清楚了,可以先看懂了再来)
有一组数,a1,a2,a3,an,逆序对的定义:如果i<j&&ai>aj的有序对。
1.很容易想到,把整个数组遍历一遍,用两个for循环,那么复杂度是o(n^2),对于题目中n的范围只能拿部分分。
2.归并排序(这里不多介绍了)蒟蒻只会数状数组
3.重头戏--树状数组+离散化
以题目的样例来看
6
5 4 2 6 3 1
下标:、
1 2 3 4 5 6
离散化操作
用b[n]数组储存每个数,a[n]数组储存下标
我们规定a[n]数组排序是b[n]数组大小来排的,也即是哪个b[n]大哪个a[n]排前面。
用c++的sort(...)(c++ stl yyds!)
这样得到a[n]
4 1 2 5 3 6
然后把a[n]放进树状数组,每放一次算一次sum。
这样做好处就是放入一个数时,后面那个数一定小于它,这个时候只需要比较下标就可以知道逆序对(我们已经按照数的大小排好了下标顺序),每次放入一个数,只需要把它的位置++就好,++就代表这个位置存在几个同一元素,接着计算sum(a[i]-1),也就是排在它前面的下标从0开始,到它的下标减一有多少个数(比较下标)。
ans+=sum(a[i]-1)
例如:
我们把4放入后,计算sum(3),发现是0,那么继续
1放入,计算sum(0),发现是0,继续
2放入,计算sum(1),发现是1,ans=1
5放入,计算sum(4),发现是3,ans=4
3放入,计算sum(2),发现是2,ans=6
6放入,计算sum(5),发现是5,ans=11
到此,答案就出来了,ans=11
那么这个问题基本就解决了。
细节问题
1.测试中可能会爆int,那么就用long long(不要问我怎么知道的,反正wa了一片的时候我还以为答案错了)
2.可能会出现同一个元素而且不同位置,解决办法:stable_sort(...)
接下来放代码qwq,树状数组模板
void add(long long x)
{
while(x<=n)
{
c[x]++; //对于每一个数,我们只需要让这个位置的值++就好因为我们最后会算sum
x+=lowbit(x);
}
}
bool cmp(const long long &x,const long long &y)
{
return b[x]>=b[y];
}
long long sum(long long x)
{
long long cnt=0;
while(x>0)
{
cnt+=c[x];
x-=lowbit(x);
}
return cnt;
}
没了。
你问我主函数去哪了,这个我这个蒟蒻没必要展示我的糟糕代码了。
其实不想放。。。