JZOJ 4307. 【NOIP2015模拟11.3晚】喝喝喝
题目
Description
Input
Output
Sample Input
3 2
5 3 1
Sample Output
4
Data Constraint
题解
首先看一条显而易见的性质,若满足
,则
,且
。
为了求答案方便,每次循环到
时,加上以
结尾的满足条件子数组的个数。
怎么求?
我们不难发现,假设当前以
结尾的满足条件子数组的开头最小可到
,则以
结尾的满足条件子数组的开头最小只能到
,否则其中必包含“坏对”。
则我们设一个指针
,表示当前满足条件子数组的开头最小为
,
是满足递增的。
考虑如何将
后移。
找到
前最后一个
满足
是一个坏对,也就是
。
设
,表示
,且没有满足条件的更小的
,也就是最后一个满足
的
。
更新
时,判断
与
的大小关系,取较大值。
更新
数组时,用
的时间,将所有的
(
)。
又有一个问题,
也是一个“坏对”,也就是
,但用这种方法判断不出。
所以再用一个变量维护最后一个出现
的位置。
代码
#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;
}