zoukankan      html  css  js  c++  java
  • 【洛谷P5488】差分与前缀和

    题目

    题目链接:https://www.luogu.com.cn/problem/P5488
    给定一个长为 (n) 的序列 (a),求出其 (k) 阶差分或前缀和。
    结果的每一项都需要对 (1004535809) 取模。
    (nleq 10^5,1le k le 10^{2333}, k ot equiv 0 pmod{1004535809})

    思路

    我们把 (a_i) 看做一个多项式的第 (i) 项系数。也就是

    [F(x)=sum^{n}_{i=1}a_ix^i ]

    前缀和和差分分开来做。

    Part 1.前缀和

    我们要求它的前缀和。也就是给上式乘上 ((1+x+x^2+x^3+cdots x^n)^k)
    由于 (1+x+x^2+x^3+cdots x^n=frac{1}{1-x}),所以我们所求就是 (F imes frac{1}{(1-x)^k})

    [frac{1}{(1-x)^k}=sum^{+infty}_{i=0}(-1)^ifrac{(-1)^i·(k+1-i)^underline{i}}{i!}x^i=sum^{+infty}_{i=0}frac{(k-i+1)^underline{i}}{i!}x^i ]

    由于

    [frac{(k-i+1)^underline{i}}{i!}=egin{pmatrix}k+i-1\iend{pmatrix} ]

    所以

    [frac{1}{(1-x)^k}=sum^{+infty}_{i=0}egin{pmatrix}k+i-1\iend{pmatrix}x^i ]

    组合数递推,然后就是卷积的形式了。上 NTT 即可。

    Part 2.差分

    同理,等价于求 (F imes (1-x)^k)
    由二项式定理得

    [(1-x)^k=sum^{+infty}_{i=0}1^{k-i}(-1)^{i}x^iegin{pmatrix}k\iend{pmatrix}=sum^{+infty}_{i=0}(-1)^{i}egin{pmatrix}k\iend{pmatrix}x^i ]

    照样可以递推做。然后也是 NTT。

    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=300010,MOD=1004535809,G=3,Ginv=334845270;
    int n,m,type,len,lim,rev[N];
    ll f[N],g[N];
    char s[N];
    
    ll fpow(ll x,ll k)
    {
    	ll ans=1;
    	for (;k;k>>=1,x=x*x%MOD)
    		if (k&1) ans=ans*x%MOD;
    	return ans;
    }
    
    void NTT(ll *f,int tag)
    {
    	for (int i=0;i<lim;i++)
    		if (i<rev[i]) swap(f[i],f[rev[i]]);
    	for (int k=1;k<lim;k<<=1)
    	{
    		ll tmp=fpow((tag==1)?G:Ginv,(MOD-1)/(k<<1));
    		for (int i=0;i<lim;i+=(k<<1))
    		{
    			ll w=1;
    			for (int j=0;j<k;j++,w=w*tmp%MOD)
    			{
    				ll x=f[i+j],y=w*f[i+j+k]%MOD;
    				f[i+j]=(x+y)%MOD; f[i+j+k]=(x-y)%MOD;
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%s%d",&n,s,&type);
    	len=strlen(s);
    	for (int i=0;i<len;i++) m=(10LL*m+s[i]-48)%MOD;
    	for (int i=1;i<=n;i++) scanf("%lld",&f[i]);
    	lim=1;
    	while (lim<=2*n) lim<<=1;
    	for (int i=0;i<lim;i++)
    		rev[i]=(rev[i>>1]>>1)|((i&1)?(lim>>1):0);
    	g[1]=1;
    	if (!type)
    	{
    		for (int i=1;i<n;i++)
    			g[i+1]=g[i]*(m+i-1)%MOD*fpow(i,MOD-2)%MOD;
    	}
    	else
    	{
    		for (int i=1;i<n;i++)
    			g[i+1]=-g[i]*(m-i+1)%MOD*fpow(i,MOD-2)%MOD;
    	}
    	NTT(f,1); NTT(g,1);
    	for (int i=0;i<lim;i++) f[i]=f[i]*g[i]%MOD;
    	NTT(f,-1);
    	ll inv=fpow(lim,MOD-2);
    	for (int i=2;i<=n+1;i++)
    		printf("%lld ",(f[i]*inv%MOD+MOD)%MOD);
    	return 0;
    }
    
  • 相关阅读:
    Git for Android Studio 学习笔记
    ACM-线段树区间更新+离散化
    hdu 1394 逆序数(线段树)
    Android瀑布流照片
    Android照片墙-多图加载
    Android-加载图片避免OOM
    Android-自定义View实现ImageView播放gif
    maven---工程建立及目录添加--
    oracle--视图(2)---
    Hibernate---Hql查询2---
  • 原文地址:https://www.cnblogs.com/stoorz/p/14234986.html
Copyright © 2011-2022 走看看