Description
给定nnn个数,从中选出三个数,使得最大的那个减最小的那个的值小于等于ddd,问有多少种选法。
Input
第一行两个整数n,dn,dn,d
第二行nnn个整数满足aia_iai,数据保证a单调递增。
(1≤n≤105,1≤d≤109,∣ai∣≤109)(1\le n\le 10^5,1\le d\le 10^9,|a_i|\le 10^9)(1≤n≤105,1≤d≤109,∣ai∣≤109)
Output
输出一个整数表示满足条件的选法。
Sample Input
4 3
1 2 3 4
Sample Output
4
Solution
给aaa序列升序排,考虑所选最小值为aia_iai时的方案数,令fif_ifi为满足afi−ai≤da_{f_i}-a_i\le dafi−ai≤d的最大编号,那么另外两个值从[ai+1,afi][a_{i+1},a_{f_i}][ai+1,afi]中选取即可,方案数Cfi−i2C_{f_i-i}^2Cfi−i2,注意到fif_ifi随iii的增加不减,故直接游标法维护fif_ifi即可,时间复杂度O(nlogn)O(nlogn)O(nlogn)
Code
#include<cstdio>
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;
}