题目
题解
题意
给出一个长度为
n
n
n的数组
a
a
a
定义
{
a
[
x
]
,
a
[
y
]
}
\{a[x],a[y]\}
{a[x],a[y]}为坏对当且仅当
x
<
y
x<y
x<y且
a
x
%
a
y
=
k
a_x\%a_y=k
ax%ay=k
问有多少连续子数组不包含坏对
分析
正难则反
思考有多少连续子数组包含坏对
将
a
x
%
a
y
=
k
a_x\%a_y=k
ax%ay=k转换成
a
x
−
k
=
p
∗
a
y
a_x-k=p*a_y
ax−k=p∗ay
很明显
a
y
a_y
ay必须要
≥
k
≥k
≥k
那么我们可以暴力枚举
p
p
p
用一个桶记录
a
x
−
k
a_x-k
ax−k的下标
如果桶内有
p
∗
a
y
p*a_y
p∗ay
那么记录最大的下标
记为
l
[
i
]
l[i]
l[i]
注意,在开始的时候,
l
[
i
]
=
l
[
i
−
1
]
l[i]=l[i-1]
l[i]=l[i−1]
因为即使当前这个位置找不到坏对
那么也要帮上一个位置统计答案
最后坏对的数量就是
∑
i
=
1
n
l
[
i
]
\sum_{i=1}^nl[i]
∑i=1nl[i]
再用总的数量减去坏对的数量就是答案
Code
#include<cstdio>
#include<iostream>
using namespace std;
long long i,j,n,k,mx,ans,all,pos,l[500005],t[500005],a[500005];
int main()
{
freopen("drink.in","r",stdin);
freopen("drink.out","w",stdout);
scanf("%lld%lld",&n,&k);
for (i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
mx=max(mx,a[i]);
}
for (i=1;i<=n;i++)
{
l[i]=max(l[i],l[i-1]);
pos=0;
if (a[i]<k) continue;
for (j=0;j*a[i]<=mx;j++)
if (t[j*a[i]]!=0)
pos=max(pos,t[j*a[i]]);
t[a[i]-k]=i;
l[i]=max(l[i],pos);
}
for (i=1;i<=n;i++)
if (l[i]!=0) ans+=l[i];
all=n*(n+1)/2;
printf("%lld\n",all-ans);
fclose(stdin);
fclose(stdout);
return 0;
}