首页 > 其他分享 >【XSY4058】区间加区间(分块FFT)

【XSY4058】区间加区间(分块FFT)

时间:2022-10-31 07:35:44浏览次数:80  
标签:ch XSY4058 int FFT poly 区间 inline mod

题面

区间加区间

题解

考虑若操作是将 \(a_1,\cdots,a_n\) 加到 \(b_l,\cdots,b_{l+n-1}\),我们可以记录每个 \(l\) 被操作的次数 \(c_l\),那么最后的 \(b_i=\sum_{j=1}^n a_jc_{i-j+1}\),可以直接 FFT 优化到 \(O(n\log n)\)。

但现在是选 \(a\) 中的一段位置加到 \(b\) 中的一段位置,那么直接对 \(a\) 分块即可,然后变成散块单调加和整块加到 \(b\) 中的某一段位置上。假设块长为 \(B\),那么时间复杂度为 \(O((n\log n+m)(n/B)+mB)=O(\sqrt{nm(n\log n+m)})\)。

#include<bits/stdc++.h>

#define LN 18
#define N 100010
#define M 1000010

using namespace std;

namespace modular
{
	const int mod=1004535809;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
	inline void Add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
	inline void Dec(int &x,int y){x=x-y<0?x-y+mod:x-y;}
	inline void Mul(int &x,int y){x=1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

vector<int> w[LN][2];

void init(int limit)
{
	for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
	{
		int len=mid<<1;
		int gn=poww(3,(mod-1)/len);
		int ign=poww(gn,mod-2);
		int g=1,ig=1;
		for(int j=0;j<mid;j++,Mul(g,gn),Mul(ig,ign))
			w[bit][0].push_back(g),w[bit][1].push_back(ig);
	}
}

void NTT(int *a,int limit,int opt)
{
	static int rev[N<<1];
	opt=(opt<0);
	for(int i=0;i<limit;i++)
		rev[i]=(rev[i>>1]>>1)|((i&1)*(limit>>1));
	for(int i=0;i<limit;i++)
		if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
	{
		for(int i=0,len=mid<<1;i<limit;i+=len)
		{
			for(int j=0;j<mid;j++)
			{
				int x=a[i+j],y=mul(w[bit][opt][j],a[i+mid+j]);
				a[i+j]=add(x,y),a[i+mid+j]=dec(x,y);
			}
		}
	}
	if(opt)
	{
		int tmp=poww(limit,mod-2);
		for(int i=0;i<limit;i++) Mul(a[i],tmp);
	}
}

typedef vector<int> poly;

poly Mul(const poly &a,const poly &b)
{
	static int A[N<<1],B[N<<1];
	const int sa=a.size(),sb=b.size();
	for(int i=0;i<sa;i++) A[i]=a[i];
	for(int i=0;i<sb;i++) B[i]=b[i];
	int limit=1;
	while(limit<(sa+sb-1)) limit<<=1;
	NTT(A,limit,1),NTT(B,limit,1);
	for(int i=0;i<limit;i++) Mul(A[i],B[i]);
	NTT(A,limit,-1);
	poly c(sa+sb-1);
	for(int i=0;i<sa+sb-1;i++) c[i]=A[i];
	for(int i=0;i<limit;i++) A[i]=B[i]=0;
	return c;
}

const int B=2000;

struct data
{
	int l,r,L;
}q[M];

int n,m,a[N],b[N],block[N];

void solve(int id)
{
	poly c(n-B+2);
	int bl=(id-1)*B+1;
	for(int i=1;i<=m;i++)
		if(block[q[i].l]<id&&id<block[q[i].r])
			c[q[i].L+bl-q[i].l]++;
	poly aa(B+1);
	for(int i=1;i<=B;i++) aa[i]=a[bl+i-1];
	poly res=Mul(c,aa);
	for(int i=2;i<=n+1;i++) b[i-1]+=res[i];
}

int main()
{
	n=read();
	int limit=1;
	while(limit<=n+3) limit<<=1;
	init(limit);
	for(int i=1;i<=n;i++)
		a[i]=read(),block[i]=(i-1)/B+1;
	m=read();
	for(int i=1;i<=m;i++)
	{
		int l=read(),r=read(),L=read();
		q[i].l=l,q[i].r=r,q[i].L=L;
		int bl=block[l],br=block[r];
		if(bl==br)
		{
			for(int j=l;j<=r;j++) b[L+j-l]+=a[j];
			continue;
		}
		for(int j=l,t=bl*B;j<=t;j++) b[L+j-l]+=a[j];
		for(int j=(br-1)*B+1;j<=r;j++) b[L+j-l]+=a[j];
	}
	int nB=block[n];
	for(int i=2;i<nB;i++) solve(i);
	for(int i=1;i<=n;i++) printf("%d\n",b[i]);
	return 0;
}
/*
3
1 2 3
1 
1 2 2
*/

标签:ch,XSY4058,int,FFT,poly,区间,inline,mod
From: https://www.cnblogs.com/ez-lcw/p/16842963.html

相关文章

  • 区间贪心问题总结
    区间分组这类问题指的是如何将n个互有交集的区间分成k组,使得这k组中每一组中所安排的任务不发生冲突,同时我们还希望让k尽可能的小。这种问题的解决方法是按照区间的左端点......
  • 【XSY3479】子区间(扫描线)
    题意:转化后变为:平面上给定\(n\)个关键点,\(q\)次询问一个点与其左上的每个关键点形成的矩形面积的最大值。题解:挺玄妙的一题。这里假设这\(n\)个关键点都是\(x\)......
  • 【XSY3338】game(期望,点分治,FFT)
    题面game题解首先可以看出“等概率选连通块->连通块内等概率选点”相当于“全局等概率选点”。一开始感觉无从下手,但是题目中还是给了一点提示。题目让我们输出答......
  • 803. 区间合并Acwing
    #include<iostream>#include<algorithm>#include<vector>usingnamespacestd;intn;intl,r;typedefpair<int,int>PII;vector<PII>ses;voidm(vector<PII>&segs......
  • 802. 区间和Acwing
    #include<iostream>#include<vector>#include<algorithm>usingnamespacestd;typedefpair<int,int>PII2;vector<int>q;vector<PII2>PII,PII1;constintN=3e5+10......
  • matlab 中fft的用法
    一.调用方法X=FFT(x);X=FFT(x,N);x=IFFT(X);x=IFFT(X,N)用MATLAB进行谱分析时注意:(1)函数FFT返回值的数据结构具有对称性。例:N=8;n=0:N-1;xn=[43267890];Xk=fft(xn)→Xk......
  • 【P4314】CPU监控(线段树维护区间历史信息)
    线段树维护区间历史信息的模板题。看了cmd的博客。大概思路是:由于我们需要求出历史信息,所以暴力的做法是在做区间修改时的tag我们先不合并,而是按时间顺序存一个tag......
  • 【HNOI2017】礼物(FFT)
    显然,\(y_i\)加上\(c\)可以看成是\(x_i\)减去\(c\)。所以就变成了\(x_i\)加上一个整数(可正可负)。现将\(x\)环拆成一个长度为\(2n\)的序列\(a\)(复制一遍),把\(......
  • 【CF553E】Kyoya and Train(期望dp,SPFA,FFT)
    考虑dp。发现正着dp好像不太好做,毕竟初值不太好设,而且时间一大于\(t\)费用就要加上\(x\),所以考虑倒着dp。设\(f_{u,j}\)表示现在已经到达\(u\)点,耗时\(j\),问......
  • The 2021 ICPC Asia Nanjing Regional Contest E.Paimon Segment Tree 区间合并线段树
    The2021ICPCAsiaNanjingRegionalContestE.PaimonSegmentTree区间合并线段树/维护矩阵乘法题目大意给定长度为的序列,要求支持区间加操作,同时对操作记录历史版本,查......