题意:
给你一个从 1 到 n 的数组,有 q 次操作,每次操作把数组每一个元素都加 l 、l + 1、...、r,求这些变化过程中不同数字的个数。
题解:
可以把 + l 到 + r 看成 + 0 到 + (r - l),这样就转变成了一个数组每个元素都加 1 直到加了 (r - l) 个 1。
也就是说每个数都扩大区间,求总区间的长度。我们考虑每一个数的差值,如果差值小于等于要加的数,那么这个差值就是变化过程中多出来的数;否则加多少就是多出来的数。
所以我们对差值进行排序,再做前缀和。对差值进行二分查找第一个大于 (r - l + 1) 的位置,那么答案就是,差值小于等于 (r - l + 1) 的前缀和,再加上还有剩下的数乘以 (r - l + 1)。
AC代码:
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <stack>
#include <cmath>
#include <deque>
#include <queue>
#include <list>
#include <set>
#include <map>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define line printf("---------------------------\n")
#define mem(a, b) memset(a, b, sizeof(a))
#define pi acos(-1)
using namespace std;
typedef long long ll;
const double eps = 1e-9;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 100000+10;
ll num[maxn], dip[maxn], sum[maxn], ans[maxn];
int main() {
int n;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> num[i];
}
sort(num, num + n);
dip[0] = 0;
for(int i = 1; i < n; i++) {
dip[i] = num[i] - num[i - 1];
}
sort(dip, dip + n);
sum[0] = 0;
for(int i = 1; i < n; i++) {
sum[i] = sum[i - 1] + dip[i];
}
int q;
cin >> q;
for(int i = 0; i < q; i++) {
ll ql, qr;
cin >> ql >> qr;
qr = qr - ql + 1;
int l = 0, r = n;
while(l < r) {
int mid = (l + r) >> 1;
if(dip[mid] <= qr) {
l = mid + 1;
} else {
r = mid;
}
}
ans[i] = (n - l + 1) * qr;
ans[i] += sum[l - 1];
}
cout << ans[0];
for(int i = 1; i < q; i++) {
cout << " " << ans[i];
}
cout << endl;
}