洛谷P5278 算术天才⑨与等差数列

(趁还是最优解,题解区也没有\(zkw\)跑来写一篇\(zkw\)的题解\(QWQ\))

题面

传送门

分析

Solution 1

根据题意,我们可以发现直接搞肯定不现实

那么我们考虑维护对于一个整段区间的信息,来代替每一个点的信息

所以很容易想到哈希的做法

那么这里我们可以考虑维护区间的平方和 (为什么呢,别问,问就是lxl说的)

因为我们可以发现,直接搞一个确定性做法的算法比较不好想,

所以我们就直接弄成这种正确性比较高的做法

就是一个序列是等差数列,我们可以直接改写它的平方和的形式(就是神鱼鱼的那个/kel)

然后带值进去比较两个值相不相等就行了/fad
这里我们线段树要维护的有两个值:

\(1.\)区间最小值

\(2.\)区间平方和

因为是单点修改,写起来也特别简单,这里采用常数小的\(zkw\)线段树实现

Solution 2

(复述一下\(lxl\)的正解)

这是一个确定性做法。(lxl给出的正解)

可以考虑维护区间最小值和最大值

然后把整个区间差分,维护差分数组的区间\(gcd\),而这个\(gcd\)必须等于\(k\),

易证其他情况都不满足这个区间是个等差数列。

接下来考虑重复的情况,我们可以维护一个前驱的最大值(这个前驱的值定义为数\(x\)前驱所在的位置)

(还有一种做法是一维数点,但是这样做有点慢,多一个\(log\))

那么最后判断一下就行了

Code

这里只给出第一种解法的代码 (因为第二种不会

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define int long long
const int N=1e6+5,p=998244353;
int n,m,las;
int sum[N<<2],minn[N<<2],mi,base,sqr1;
#define sqr(x) (x*x%p)
#define inc(x,y) (x+y>=p?x+y-p:x+y)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
inline void modify(int x,int k){
	minn[base+x]=k;
	sum[base+x]=sqr(k);
	for(int i=(base+x)>>1;i;i>>=1){
		minn[i]=min(minn[i<<1],minn[i<<1|1]);
		sum[i]=inc(sum[i<<1],sum[i<<1|1]);
	}
	return ;
}
inline int query1(int x,int y){
	int res=0x3f3f3f3f;
	for(int s=base+x-1,t=base+y+1;t-s>1;t>>=1,s>>=1){
		if(~s&1) res=min(res,minn[s^1]);
		if(t&1) res=min(res,minn[t^1]);
	}
	return res;
}
inline int query2(int x,int y){
	int res=0;
	for(int s=base+x-1,t=base+y+1;t-s>1;t>>=1,s>>=1){
		if(~s&1) res=inc(res,sum[s^1]);
		if(t&1) res=inc(res,sum[t^1]);
	}
	return res;
}
int QuickPow(int x){
	int res=1,y=p-2;
	while(y){
		if(y&1) res=(res*x)%p;
		x=(x*x)%p;
		y>>=1;
	}
	return res;
}
int de;
signed main(){
	read(n),read(m);de=QuickPow(6);
	base=(1<<(int)(ceil(log(n+1)/log(2))));
	for(int i=base+1;i<=base+n;i++) read(minn[i]),sum[i]=sqr(minn[i]);
	for(int i=base-1;i>=1;i--) sum[i]=inc(sum[i<<1],sum[i<<1|1]),minn[i]=min(minn[i<<1],minn[i<<1|1]);
	while(m--){
		int op,x,y,k;
		read(op),read(x),read(y);
		x^=las,y^=las;
		if(op==1) modify(x,y);
		else{
			read(k);
			k^=las;int len=y-x+1;
			mi=query1(x,y)%p,sqr1=query2(x,y)%p;
			if(inc(inc(len*sqr(mi)%p,k*mi%p*len%p*(len-1)%p),sqr(k)*de%p*(len-1)%p*len%p*((len<<1)-1)%p)==sqr1){
				las++;
				puts("Yes");
			}
			else puts("No");
		}
	}
	return 0;
}

上一篇:AtCoder Beginner Contest 191 F - GCD or MIN


下一篇:备忘录