题解 P5278 【算术天才⑨与等差数列】

· · 题解

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

题面

传送门

分析

Solution 1

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

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

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

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

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

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

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

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

$2.$区间平方和 因为是单点修改,写起来也特别简单,这里采用常数小的$zkw$线段树实现 ## Solution 2 (复述一下$lxl$的正解) 这是一个确定性做法。~~(lxl给出的正解)~~ 可以考虑维护区间最小值和最大值 然后把整个区间差分,维护差分数组的区间$gcd$,而这个$gcd$必须等于$k$, 易证其他情况都不满足这个区间是个等差数列。 接下来考虑重复的情况,我们可以维护一个前驱的最大值(这个前驱的值定义为数$x$前驱所在的位置) (还有一种做法是一维数点,但是这样做有点慢,多一个$log$) 那么最后判断一下就行了 # Code 这里只给出第一种解法的代码 ~~(因为第二种不会~~ ```cpp #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; } ```