CodeForces - 897D(二分+思維)

題意:

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章