归并:
将序列转化为多个小区间处理后再归并
二路归并
$1.$归并排序
int n;
int q[], tmp[];
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r) // 归并两个数组为一个tmp一个数组
if (q[i] <= q[j]) tmp[k ++] = q[i ++];
else tmp[k ++] = q[j ++];
while (i <= mid) tmp[k ++] = q[i ++]; // 如果q[l ~ mid]还没归并完,剩下的全部归并至tmp中
while (j <= r) tmp[k ++] = q[j ++]; // 如果q[mid ~ r]还没归并完,剩下的全部归并至tmp中
for (i = l, j = 0; i <= r; i ++, j ++) q[i] = tmp[j];
}
$2.$求逆序对数量
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 500050;
int n;
int q[N], tmp[N];
LL merge_sort(int l, int r)
{
if (l >= r) return 0;
int mid = l + r >> 1;
LL res = merge_sort(l, mid) + merge_sort(mid + 1, r);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k ++] = q[i ++];
else
{
tmp[k ++] = q[j ++];
res += mid - i + 1;
}
while (i <= mid) tmp[k ++] = q[i ++];
while (j <= r) tmp[k ++] = q[j ++];
for (i = l, j = 0; i <= r; i ++, j ++) q[i] = tmp[j];
return res;
}
int main()
{
scanf ("%d", &n);
for (int i = 0; i < n; i ++) scanf ("%d", &q[i]);
printf ("%lld", merge_sort(0, n - 1));
return 0;
}
多路归并
思路:
先找到所有等差数列合并以后的第$M$小的数$x$(注意$ \geq x$的个数可能$\geq M$),再求出前M大的数的和即可
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, m;
int a[N], b[N];
bool check(int x)
{
LL res = 0;
for (int i = 1; i <= n; i ++)
if (a[i] >= x)
res += (a[i] - x) / b[i] + 1;
return res >= m;
}
int main()
{
scanf ("%d %d", &n, &m);
for (int i = 1; i <= n; i ++) scanf ("%d %d", &a[i], &b[i]);
int l = 0, r = 1e6;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
LL res = 0, cnt = 0;
for (int i = 1; i <= n; i ++)
if (a[i] >= r)
{
int c = (a[i] - r) / b[i] + 1; // 项数
cnt += c; // 总项数
int end = a[i] - (c - 1) * b[i]; // 大于等于r的最后一个数
res += (LL) (a[i] + end) * c / 2; // 高斯求和
}
printf ("%lld", res - (cnt - m) * r);
return 0;
}