[Ynoi2012]D1T1

Posted mrsrz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Ynoi2012]D1T1相关的知识,希望对你有一定的参考价值。

题目大意:

给定一个序列$a_1,a_2,dots,a_n$,进行$m$次操作,每次操作如下:

1. 给定$x,y,z$,对所有下标为$y,y+x,y+2x,dots$的元素加上$z$(保证$yleqslant x$)。
2. 给定$l,r$,求$(sumlimits_{i=l}^r a_i)mod{1000000007}$的值。

解题思路:

分块+根号分治简单维护即可。

考虑对$x$的大小分类讨论。

若$xgeqslant sqrt n$,则我们暴力给每个位置加,需要加的次数为$O(sqrt n)$次。由于需要查询区间和,用分块维护,总修改、查询复杂度为$O(msqrt n)$。

若$x< sqrt n$,我们需要用另外的方法维护。

注意到单次修改是针对整个序列的元素,所以对$x,y$相同的修改,我们可以累加它的贡献。

那么我们每次查询的时候,需要对于所有的$x$进行一遍查询。故我们需要做到单次$O(1)$。

我们对每个$x$,维护$y$的前缀、后缀和。对于一次询问,我们可以当成把序列分成了若干个大小为$x$的块。中间的整块元素,每个块里肯定所有的$y$都有,增加的贡献就是关于$x$的修改总和。所有块的贡献相同,可以$O(1)$算。边角的话,由于我们记录了前缀、后缀和,也可以$O(1)$算。两个端点在同一个块中,则直接前缀和相减即可。

总时间复杂度$O(msqrt n)$。

C++ Code:

#include<iostream>
const int siz=512,M=siz+2,N=2e5+5,Z=N/siz+2,md=1e9+7;
#define bel(x)((x-1)/siz+1)
inline void upd(int&a){a+=a>>31&md;}
int n,blocks,L[Z],R[Z],a[N],sum[Z],m;
int pre[M][M],suf[M][M];
inline int sigma(int l,int r){
	const int bL=bel(l),bR=bel(r);
	int ret=0;
	if(bL==bR)
	for(int i=l;i<=r;++i)upd(ret+=a[i]-md);
	else{
		for(int i=R[bL];i>=l;--i)upd(ret+=a[i]-md);
		for(int i=L[bR];i<=r;++i)upd(ret+=a[i]-md);
		for(int i=bL+1;i<bR;++i)upd(ret+=sum[i]-md);
	}
	return ret;
}
int main(){
	std::ios::sync_with_stdio(0),std::cin.tie(0),std::cout.tie(0);
	std::cin>>n>>m;
	blocks=bel(n);
	for(int i=1;i<=blocks;++i)L[i]=R[i-1]+1,R[i]=i*siz;R[blocks]=n;
	for(int i=1;i<=n;++i)std::cin>>a[i];
	for(int i=1;i<=blocks;++i)
	for(int j=L[i];j<=R[i];++j)upd(sum[i]+=a[j]-md);
	while(m--){
		int op;
		std::cin>>op;
		if(op==1){
			int x,y,z;
			std::cin>>x>>y>>z,z-=md;
			if(x>=siz)
			for(int i=y;i<=n;i+=x)upd(a[i]+=z),upd(sum[bel(i)]+=z);
			else{
				int*pr=pre[x],*sf=suf[x];
				for(int i=x;i>=y;--i)upd(pr[i]+=z);
				for(int i=1;i<=y;++i)upd(sf[i]+=z);
			}
		}else{
			int l,r;
			std::cin>>l>>r;
			int ans=sigma(l,r);
			for(int i=1;i<siz;++i){
				const int bL=(l-1)/i+1,bR=(r-1)/i+1;
				if(bL==bR)upd(ans+=pre[i][(r-1)%i+1]-md),upd(ans-=pre[i][(l-1)%i]);else
				ans=(ans+(bR-bL-1LL)*pre[i][i])%md,upd(ans+=pre[i][(r-1)%i+1]-md),upd(ans+=suf[i][(l-1)%i+1]);
			}
			std::cout<<ans<<‘
‘;
		}
	}
	return 0;
}

 

以上是关于[Ynoi2012]D1T1的主要内容,如果未能解决你的问题,请参考以下文章

luogu P4688 [Ynoi2016]掉进兔子洞 bitset 莫队

[Ynoi2018]五彩斑斓的世界

Visual Studio 2012-2019的130多个jQuery代码片段。

luogu P4688 [Ynoi2016]掉进兔子洞

Ynoi

「Ynoi2015」我回来了