题目传送门
题意
- 给定一个序列,支持区间求和和跳点加(即对于 (y+kx(k in N)) 位置上加)
Sol
第一道完全没有提示做出的 Ynoi。
考虑到题目和 P3396 哈希冲突 有点像,不如先看一下那一题题解吧。
获得灵感了吗?
对于修改操作,我们仍然分两类。
- (x < sqrt n)
同样考虑记录 (f_{i}{j}) 表示 (x=i),(y=j) 的修改总和。
我们考虑统计答案。
答案即为 (sumlimits_{i=l}^r a_i+sumlimits_{i=1}^{sqrt n}sumlimits_{j=1}^i (f_{i,j} imes(leftlceil dfrac{r-j}{i} ight ceil-leftlceil dfrac{l-1-j}{i} ight ceil)))。
显然可以分开算后用前缀和优化掉一个 (sqrt n)。
用 (s_{i,j}) 表示 (f_{i,j}) 对 (j) 一维取前缀和,即 (s_{i,j}=sumlimits_{k=1}^j f_{i,k})。
答案即可表示为 (sumlimits_{i=l}^r a_i+sumlimits_{i=1}^{sqrt n}((s_{i,i} imes(leftlfloor dfrac{r}{i} ight floor-leftlfloor dfrac{l-1}{i} ight floor))+s_{i,r\%i}-s_{i,(l-1)\%r}))。
事实上这个意义比上式更好理解。(
修改处理 (s_{i,j}) 即可。
- (x ge sqrt n)
暴力修改即可。
如上式,考虑迅速求 (sumlimits_{i=l}^r a_i),那么考虑分块。
总复杂度 (O((n+m)sqrt n))。
记得开 ( ext{long long})
( ext{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 ---------- //