★题目描述
杰哥喜欢单调不下降的序列,因为他觉得这样的序列有美感。
今天杰哥得到了一个长度为NN的序列DD,但是他今天心情不好,他把序列丢给了你,要你把他变成单调不下降的序列。
你可以花费A单位的时间交换序列中两个相邻的元素,当然,你也可以选择干一半摸鱼罢工。
最后你要把序列还给杰哥,但是如果杰哥发现序列中每有一个逆序对,就会把你抓过去,训话B单位时间。
你想花最少的时间(主动交换元素+被动被杰哥训话的时间)把这个事解决了,问这个时间是多少。
逆序对的定义:存在两个整数ii和jj,满足1<=i<j<=N1<=i<j<=N,且Di>DjDi>Dj,则 <Di,Dj><Di,Dj> 这个有序对称为 DD 的一个逆序对。
★输入格式
输入第一行为三个空格隔开的正整数 N、A、B,代表序列长度为N,A和B的含义见题面。
接下来一行有 N 个整数,第i个数表示序列的第ii个元素DiDi。
对于80%的数据,1<=N,A,B<=20001<=N,A,B<=2000。
对于100%的数据,1<=N,A,B<=1000001<=N,A,B<=100000,序列元素非负且在int范围内。
★输出格式
输出你要花费的最少时间。
★样例输入
2 1 2
2 1
★样例输出
1
解法:
先弄懂逆序对的含义,其实最重要的一点就是,逆序对的数量就是要交换相邻达到非递减的最小交换次数,也就是说每交换一次,逆序对就会少一对。
因此本题其实根本不是贪心算法或者动态规划,就是求出所有的逆序对数量,然后看是交换代价小还是训话代价小,要么全部交换,要么全部训话。
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int N = 100000; int a[N], tmp[N]; int ans; void Merge(int l, int m, int r) { int i = l; int j = m + 1; int k = l; while (i <= m && j <= r) { if (a[i] > a[j]) { tmp[k++] = a[j++]; ans += m - i + 1; } else { tmp[k++] = a[i++]; } } while (i <= m) tmp[k++] = a[i++]; while (j <= r) tmp[k++] = a[j++]; for (int i = l; i <= r; i++) a[i] = tmp[i]; } void Merge_sort(int l, int r) { if (l < r) { int m = (l + r) >> 1; Merge_sort(l, m); Merge_sort(m + 1, r); Merge(l, m, r); } } int main() { int n, A, B; cin >> n >> A >> B; for (int i = 0; i < n; i++) { cin >> a[i]; } ans = 0; Merge_sort(0, n - 1); if (A < B) ans = ans * A; else ans = ans * B; cout << ans << endl; return 0; }
最后得分是8分。分析了原因是最后两个点数据大,溢出了。
改进思路:
把所有的int型,改成long型,解决溢出问题,10分。