題意:
給你一個從 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;
}