题目链接:http://codeforces.com/contest/1119/problem/D
题目大意:
有N行数,每行有1E18+1个数。
第i行数以Si开头,并且是一个等差为1的递增数列,比如第i行的数字为Si,Si+1,Si+2,Si+3…
现在有q个询问,每个询问给出l和r,问在这N行数中,第l到第r列中有多少个不同的数。
题解:
令w=r-l+1.
对于第i行数,如果s[i+1]-s[i]比w大的话,那么其贡献只能为w;如果s[i+1]-s[i]比w小,那么其贡献为s[i+1]-s[i].
即第i行数对答案的贡献为min(s[i+1]-s[i],r-l+1).
令d[i]=s[i+1]-s[i].(i<n)
则第i行数的贡献为min(d[i],w).
Ans=
∑
i
=
1
n
m
i
n
(
d
[
i
]
,
w
)
\sum_{i=1}^n{min(d[i],w)}
∑i=1nmin(d[i],w)
可以转换为
∑
i
=
1
w
i
∗
T
(
i
)
\sum_{i=1}^w{i*T(i)}
∑i=1wi∗T(i)+
∑
i
=
w
+
1
+
∞
w
∗
T
(
i
)
\sum_{i=w+1}^{+∞}{w*T(i)}
∑i=w+1+∞w∗T(i)
其中T(i)表示i在d[0…n-1]中出现的次数
则可以提前统计i*T(i)的前缀和,二分找到位置后直接得到答案
代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n;
long long int s[maxn];
long long int d[maxn];
long long int pre[maxn];
int q;
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for(int i=0;i<n;i++)
cin >> s[i];
sort(s+0,s+n);
for(int i=0;i<n-1;i++)
d[i]=s[i+1]-s[i];
sort(d+0,d+n-1);
pre[0]=d[0];
for(int i=1;i<n-1;i++)
pre[i]=pre[i-1]+d[i];
cin >> q;
long long int l,r;
while(q--)
{
cin >> l >> r;
long long int w=r-l+1;
int plz=lower_bound(d,d+n-1,w+1)-d-1;
long long int ans=pre[plz];
ans+=w*(n-plz-1);
cout << ans << ' ';
}
cout << endl;
return 0;
}