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

本文详细解析了JZOJ4307题目“喝喝喝”的解题思路,通过分析子数组特性,利用动态更新指针和坏对概念,实现了高效的算法设计。文章涵盖了数据约束、样例输入输出及代码实现。

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

题目

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

3 2
5 3 1

Sample Output

4

Data Constraint

在这里插入图片描述

题解

首先看一条显而易见的性质,若满足xmod  y=kx \mod y=kxmody=k,则y∣x−ky|x-kyxk,且y>ky>ky>k
为了求答案方便,每次循环到iii时,加上以iii结尾的满足条件子数组的个数。
怎么求?
我们不难发现,假设当前以iii结尾的满足条件子数组的开头最小可到xxx,则以i+1i+1i+1结尾的满足条件子数组的开头最小只能到xxx,否则其中必包含“坏对”。
则我们设一个指针lastlastlast,表示当前满足条件子数组的开头最小为lastlastlastlastlastlast是满足递增的。
考虑如何将lastlastlast后移。
找到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]−ka[i]|a[l]-ka[i]a[l]k
f[i]=lf[i]=lf[i]=l,表示i∣a[l]−ki|a[l]-kia[l]k,且没有满足条件的更小的lll,也就是最后一个满足i∣a[l]−ki|a[l]-kia[l]klll
更新lastlastlast时,判断f[a[i]]f[a[i]]f[a[i]]lastlastlast的大小关系,取较大值。
更新fff数组时,用a[i]\sqrt{a[i]}a[i]的时间,将所有的f[j]=if[j]=if[j]=ij∣a[i]−kj|a[i]-kja[i]k)。
又有一个问题,(2,5)(2,5)(2,5)也是一个“坏对”,也就是a[x]=ka[x]=ka[x]=k,但用这种方法判断不出。
所以再用一个变量维护最后一个出现a[l]=ka[l]=ka[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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值