JZOJ 4307. 【NOIP2015模拟11.3晚】喝喝喝
题目
Description
Input
Output
Sample Input
3 2
5 3 1
Sample Output
4
Data Constraint
题解
首先看一条显而易见的性质,若满足
x
m
o
d
  
y
=
k
x \mod y=k
xmody=k,则
y
∣
x
−
k
y|x-k
y∣x−k,且
y
>
k
y>k
y>k。
为了求答案方便,每次循环到
i
i
i时,加上以
i
i
i结尾的满足条件子数组的个数。
怎么求?
我们不难发现,假设当前以
i
i
i结尾的满足条件子数组的开头最小可到
x
x
x,则以
i
+
1
i+1
i+1结尾的满足条件子数组的开头最小只能到
x
x
x,否则其中必包含“坏对”。
则我们设一个指针
l
a
s
t
last
last,表示当前满足条件子数组的开头最小为
l
a
s
t
last
last,
l
a
s
t
last
last是满足递增的。
考虑如何将
l
a
s
t
last
last后移。
找到
a
[
i
]
a[i]
a[i]前最后一个
a
[
l
]
a[l]
a[l]满足
(
a
[
l
]
,
a
[
i
]
)
(a[l],a[i])
(a[l],a[i])是一个坏对,也就是
a
[
i
]
∣
a
[
l
]
−
k
a[i]|a[l]-k
a[i]∣a[l]−k。
设
f
[
i
]
=
l
f[i]=l
f[i]=l,表示
i
∣
a
[
l
]
−
k
i|a[l]-k
i∣a[l]−k,且没有满足条件的更小的
l
l
l,也就是最后一个满足
i
∣
a
[
l
]
−
k
i|a[l]-k
i∣a[l]−k的
l
l
l。
更新
l
a
s
t
last
last时,判断
f
[
a
[
i
]
]
f[a[i]]
f[a[i]]与
l
a
s
t
last
last的大小关系,取较大值。
更新
f
f
f数组时,用
a
[
i
]
\sqrt{a[i]}
a[i]的时间,将所有的
f
[
j
]
=
i
f[j]=i
f[j]=i(
j
∣
a
[
i
]
−
k
j|a[i]-k
j∣a[i]−k)。
又有一个问题,
(
2
,
5
)
(2,5)
(2,5)也是一个“坏对”,也就是
a
[
x
]
=
k
a[x]=k
a[x]=k,但用这种方法判断不出。
所以再用一个变量维护最后一个出现
a
[
l
]
=
k
a[l]=k
a[l]=k的位置。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int f[100010],a[100010];
int main()
{
int n,k,i,j,last=0,p=0;
long long ans=0;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=1;i<=n;i++)
{
if(a[i]>k&&f[a[i]]>last) last=f[a[i]];
if(a[i]>k&&p>last) last=p;
ans+=i-last;
int t=a[i]-k;
if(a[i]==k) p=i;
for(j=1;j<=floor(sqrt(t));j++) if(t%j==0) f[j]=f[t/j]=i;
}
printf("%lld",ans);
return 0;
}