JZOJ 4307. 【NOIP2015模拟11.3晚】喝喝喝

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 yxk,且 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 ia[l]k,且没有满足条件的更小的 l l l,也就是最后一个满足 i ∣ a [ l ] − k i|a[l]-k ia[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 ja[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;
}
posted @ 2018-10-06 20:52  AnAn_119  阅读(58)  评论(0编辑  收藏  举报