题意:有一个长度为n的乱序集合,如果一个子序列为逆序,你就要付x元,或者你可以选择修改一个相邻的数字,你就要付y元,问最少你要付多少钱。(其实你交换一个存在逆序的相邻数字就可以减少一个逆序数)
这题不知道是题目的意思太绕还是怎样,我看了很久硬是每看懂题目在讲什么,后来看了一下大佬们的代码和解释才知道,这不就是树状数组的入门题吗。。我。。。英语和语文阅读能力大概是没救了。。。
思路:就是算这个集合存在多少逆序数,最后的答案乘min(x,y)就可以了。(好像应该也可以用线段树做,不过这个就是数组数组的板子题)
AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int c[maxn],a[maxn],b[maxn];
int n, x, y;
ll lowbit(int x){
return x&(-x);
}
void add(int x,int y){
for(int i = x; i <= n; i+=lowbit(i))
c[i] += y;
}
ll query(int x){
ll ans = 0;
for(int i = x; i > 0; i-=lowbit(i))
ans += c[i];
return ans;
}
int main(){
int i;
while(scanf("%d%d%d",&n,&x,&y)!=EOF){
memset(c, 0, sizeof(c));
for(i = 1; i <= n; i++){
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b+1, b+1+n);
ll ans = 0;
for(i = n; i > 0; i--){ //这里要从n开始,因为可能存在相同的数字,把数字按原本位置从后往前插入树状数组,查看在它原本位置后面有多少个小于它的数,就存在多少逆序数
int t = lower_bound(b+1, b+1+n, a[i])-b; //找到第一个大于等于a[i]的数的位置,所以查询的时候要减1
ans += query(t-1);
add(t, 1);
}
printf("%lld\n",ans*min(x,y));
}
return 0;
}