[JZOJ4307]喝喝喝--枚举

[JZOJ4307]喝喝喝--枚举

题目链接

自行搜索

分析

我们需要找到所有不包含\((a_x,a_y),a_x \equiv k \mod a_y (x<y)\)这样的连续数对,转化一下变成\(a_x-k \equiv 0 \mod a_y\).

考虑从左到右加数,可以发现如果\(a_i - k \equiv 0 \mod a_j\),那么起点为\(i\),终点大于等于\(j\)的连续序列都是不合法的,于是维护一个左指针\(lst\),表示当前距离最近的不合法起点,换句话说,\(lst+1\)到当前遍历的数这一段都是合法的

怎么更新\(f[x]\)?由于值域范围很小\((1e5)\),我们设若当前加的第\(i\)个数为\(x\),设\(f[x]\)为当前距\(i\)最近的\(y\)使得\(x - k \equiv 0 \mod a_y\),每次新加入一个数就比较\(f[x]\)\(lst\)哪个更大,这样就能更新\(lst\),同时加完\(x\)这个数后,我们可以在\(O( \sqrt{x} )\)的时间内将所有满足\(x -k \equiv 0 \mod p\)\(p\)找出来更新它们的\(f\)

当时要注意我们这种方法会漏掉前面有数为\(k\)的情况,要特判

代码

/*
  code by RyeCatcher
*/
inline char gc(){
    static char buf[SIZE],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
    while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=1000005;
const int inf=0x7fffffff;
int f[maxn],kk=0,lst=0;
int n,k;
ll ans=0;
int main(){
	int x;
	FO(drink);
	//freopen("drink6.in","r",stdin);
	read(n),read(k);
	for(ri i=1;i<=n;i++){
		read(x);
		if(x>k){
			if(f[x]>lst)lst=f[x];
			if(kk>lst)lst=kk;
		}
		ans+=i-lst;
		if(x==k)kk=i;
		else if(x<k)continue;
		x-=k;
		for(ri j=1;j<sqrt(x+0.5);j++){
			if(x%j==0)f[j]=f[x/j]=i;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

posted @ 2018-10-17 22:40  Rye_Catcher  阅读(131)  评论(0编辑  收藏  举报