题目链接:http://codeforces.com/contest/1119/problem/D

 

题意: 

         还是得要认真读题啊,比赛时看这题目,做的心情都没有,后来认真仔细的读一下,还是挺好理解的。就是每个音符长都是1e18+1,给你n个音符的开头,比如一个音符的开头是3,那么它就是3,4,5,6.。。。。。。

然后给你q个问题,每次询问区间L,R中有多少个不同的音阶,这个区间不理解的看一下题目中的图,图的上方标出l区间的序号(0,1,2,4。。。。)

 

思路:

        如果只有一个音符,那么就有(R-L+1)个不同的音阶,而如果有两个音符的话,有多少呢。很显然,如果他们的开头相同,那么这两个音符就是相同的,而如果他们的开头不同的话,那么,当他们的开头的差不超过区间的的长度时就会有重复的部分,否则就没有重复的部分。

可以这样理解,我们以开头最小的一个为一个基础,那么这个有了(R-L+1)个,第二个音符在第一个音符的基础上多了多少个不同的音阶呢?很显然如果设一个开头是a1,第二个是a2,那么就多了min(a2-a1,R-L+1);

于是当有n个音符时,我们可以这样考虑,首先把开头从小到大排序,并且去重,之后计算两两之间的差b[i],再把b从小到大排序,计算他们的前缀和sum[i],之后对于每一次询问,我们,以最小的一个开头为基础,之后在b中二分查找第一个大于区间长的值,分别计算出结果加上即可。

具体请参看代码:

#include<bits/stdc++.h>
using namespace std;

#define ll long long
typedef pair<int, int> p;
const int maxn = 1000*100  + 10;
const int mod = 1e9 + 7;
int n, m;
ll a[maxn],b[maxn],sum[maxn];
vector<ll>v;

int main() {

	ios::sync_with_stdio(false);
	cin >> n ;
	for (int i = 1; i <= n; i++)cin>>a[i];
	sort(a + 1, a + 1 + n);
	int cnt = 1;      //计数去重后的个数+1
	for (int i = 2; i <= n; i++) {
		if (a[i] == a[i - 1])continue; //去重
		b[cnt] = a[i] - a[i - 1];		//计算差值
		cnt++;
	}
	sort(b+1,b+cnt);
	sum[0] = 0;
	for(int i=1;i<cnt;i++)
		sum[i] = sum[i - 1] + b[i];    //计算前缀和
	
	cin >> m;
	ll L, R;
	while (m--) {
		cin >> L >> R;
		ll ans = 0;
		ans += (R-L+1);    //以最小的一个为基础先加上区间长
		ll k = upper_bound(b+1,b+cnt,R-L)-b; //查找第一个比区间长大的第一个数的位置
		ans += sum[k-1];			//前面的之间加上前缀和即可
		ans += (R-L+1)*(cnt - k);    //后面的因为大于区间长,但对于每一个音符来说,最多只有(R-L+1)个不同的音阶
		cout << ans <<' ';
	}

	return 0;
}