Newcoder 84 F.选值(水~)

Description

给定 n n n个数,从中选出三个数,使得最大的那个减最小的那个的值小于等于 d d d,问有多少种选法。

Input

第一行两个整数 n , d n,d n,d

第二行 n n n个整数满足 a i a_i ai,数据保证a单调递增。

( 1 ≤ n ≤ 1 0 5 , 1 ≤ d ≤ 1 0 9 , ∣ a i ∣ ≤ 1 0 9 ) (1\le n\le 10^5,1\le d\le 10^9,|a_i|\le 10^9) (1n105,1d109,ai109)

Output

输出一个整数表示满足条件的选法。

Sample Input

4 3
1 2 3 4

Sample Output

4

Solution

a a a序列升序排,考虑所选最小值为 a i a_i ai时的方案数,令 f i f_i fi为满足 a f i − a i ≤ d a_{f_i}-a_i\le d afiaid的最大编号,那么另外两个值从 [ a i + 1 , a f i ] [a_{i+1},a_{f_i}] [ai+1,afi]中选取即可,方案数 C f i − i 2 C_{f_i-i}^2 Cfii2,注意到 f i f_i fi i i i的增加不减,故直接游标法维护 f i f_i fi即可,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

Code

#include
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,d,a[maxn];
int main()
{
	scanf("%d%d",&n,&d);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	ll ans=0;
	for(int i=1,pos=1;i<=n;i++)
	{
		while(pos<=n&&a[pos]-a[i]<=d)pos++;
		pos--;
		ans+=(ll)(pos-i)*(pos-i-1)/2;
	}
	printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(Newcoder,水题)