[Ynoi2011]初始化

题目传送门

题意

  • 给定一个序列,支持区间求和和跳点加(即对于 \(y+kx(k \in N)\) 位置上加)

Sol

第一道完全没有提示做出的 Ynoi。

考虑到题目和 P3396 哈希冲突 有点像,不如先看一下那一题题解吧。

获得灵感了吗?

对于修改操作,我们仍然分两类。

  1. \(x < \sqrt n\)

同样考虑记录 \(f_{i}{j}\) 表示 \(x=i\)\(y=j\) 的修改总和。

我们考虑统计答案。

答案即为 \(\sum\limits_{i=l}^r a_i+\sum\limits_{i=1}^{\sqrt n}\sum\limits_{j=1}^i (f_{i,j}\times(\left\lceil \dfrac{r-j}{i}\right\rceil-\left\lceil \dfrac{l-1-j}{i}\right\rceil))\)

显然可以分开算后用前缀和优化掉一个 \(\sqrt n\)

\(s_{i,j}\) 表示 \(f_{i,j}\)\(j\) 一维取前缀和,即 \(s_{i,j}=\sum\limits_{k=1}^j f_{i,k}\)

答案即可表示为 \(\sum\limits_{i=l}^r a_i+\sum\limits_{i=1}^{\sqrt n}((s_{i,i}\times(\left\lfloor \dfrac{r}{i}\right\rfloor-\left\lfloor \dfrac{l-1}{i}\right\rfloor))+s_{i,r\%i}-s_{i,(l-1)\%r})\)

事实上这个意义比上式更好理解。(

修改处理 \(s_{i,j}\) 即可。

  1. \(x \ge \sqrt n\)

暴力修改即可

如上式,考虑迅速求 \(\sum\limits_{i=l}^r a_i\),那么考虑分块。

总复杂度 \(O((n+m)\sqrt n)\)

记得开 \(\text{long long}\)

\(\text{Code}\)

// wish to get better qwq

#include<bits/stdc++.h>
#define re register int
#define pb push_back

using namespace std;
typedef long long ll;

template <typename T> void rd(T &x){
	ll fl=1;x=0;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') fl=-fl;
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	x*=fl;
}
void wr(ll x){
	if(x<0) x=-x,putchar('-');
	if(x<10) putchar(x+'0');
	if(x>9) wr(x/10),putchar(x%10+'0');
}

// ---------- IO ---------- //

const int N=2e5+5,SQ=505,mod=1e9+7;
int n,m,op,l,r,qaq,len,tot;
ll a[N],sum[SQ],s[SQ][SQ];
// s[i][j] 指 x=i [1,j] 中 add 的值 

inline int block(int x){return (x-1)/len+1;}
inline int L(int x){return (x-1)*len+1;}
inline int R(int x){return x*len;}

inline void modify(int x,int y,int z){
	if(x>=tot){
		for(re i=y;i<=n;i+=x) a[i]+=z,sum[block(i)]+=z;
		return ;
	}
	for(re i=y;i<=x;i++) s[x][i]+=z;
//	cout<<x<<' '<<y<<' '<<z<<endl;
//	for(re i=0;i<=x;i++) cout<<s[x][i]<<' ';cout<<endl;
	return ;
}

inline ll query(int l,int r){
	ll ans=0;int lb=L(block(l)+1),rb=R(block(r)-1),tmp=block(r)-1;
	if(block(l)==block(r)){
		for(re i=l;i<=r;i++) ans+=a[i];
	}
	else{
		for(re i=l;i<lb;i++) ans+=a[i];
		for(re i=rb+1;i<=r;i++) ans+=a[i];
		for(re i=block(l)+1;i<=tmp;i++) ans+=sum[i];
	}
//	cout<<ans<<endl;
	for(re i=1;i<=tot;i++) ans+=s[i][r%i]-s[i][(l-1)%i]+s[i][i]*(r/i-(l-1)/i);
	return ans;
}

// ---------- Sqrt & Operations ---------- //

int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	rd(n);rd(m);len=(int)sqrt(n);tot=block(n);
	for(re i=1;i<=n;i++) rd(a[i]),sum[block(i)]+=a[i];
	for(re i=1;i<=m;i++){
		rd(op);rd(l);rd(r);
		if(op==1) rd(qaq),modify(l,r,qaq);
		else wr(query(l,r)%mod),puts("");
	}
	return 0;
}

// ---------- Main ---------- //

posted @ 2021-02-18 10:18  Demoe  阅读(103)  评论(0编辑  收藏  举报