• Codeforces446C


    Portal

    Description

    给出一个(n(nleq3 imes10^5))个数的序列,进行(m(mleq3 imes10^5))次操作,操作有两种:

    • 给区间([L,R])加上一个斐波那契数列,即({a_L,a_{L+1},...,a_R} ightarrow {a_L+F_1,a_{L+1}+F_2,...,a_R+F_{R-L+1}})
    • 询问区间([L,R])的和,对(10^9+9)取模。
      斐波那契数列:(F_1=1,F_2=2)且满足(F_{n+2}=F_n+F_{n+1})

    Solution

    容易知道,满足(a_{n+2}=a_n+a_{n+1})的数列具有以下性质:

    • (c_n=a_n+b_n),则(c_1=a_1+b_1,c_2=a_2+b_2,c_{n+2}=c_n+c_{n+1})
    • 有通项公式(a_n=F_{n-2}a_1+F_{n-1}a_2)
    • 有前缀和公式(sum_{i=1}^n a_i=a_{n+2}-a_2)

    下面依次进行证明。
    证明1
    (c_{n+2}=a_{n+2}+b_{n+2}=(a_n+a_{n+1})+(b_n+b_{n+1})=(a_n+b_n)+(a_{n+1}+b_{n+1})=c_n+c_{n+1})
    证明2
    若当(nleq k)时,(a_n=F_{n-2}a_1+F_{n-1}a_2),则
    (a_{k+1}=a_{k-1}+a_k=(F_{k-3}a_1+F_{k-2}a_2)+(F_{k-2}a_1+F_{k-1}a_2)=F_{k-1}a_1+F_ka_2)
    因为(a_1=F_{-1}a_1+F_0)(可以认为(F_0=F_2-F_1=0,F_{-1}=F_1-F_0=1)),(a_2=F_0a_1+F_1a_2)
    所以(forall ninmathbb{Z},a_n=F_{n-2}a_1+F_{n-1}a_2)
    证明3
    (egin{align} 2Sigma_{i=1}^n a_i &= (a_1+a_2+...+a_n)+(a_1+a_2+...+a_n) \ &=a_1+(a_1+a_2)+(a_2+a_3)+...+(a_{n-1}+a_n)+a_n \ &=a_1+a_n+(a_3+a_4...+a_{n+1}) \ &=(a_1+a_2+...+a_n)-a_2+a_n+a_{n+1} \ &=Sigma_{i=1}^n a_i+a_{n+2}-a_2 \ Sigma_{i=1}^n a_i &=a_{n+2}-a_2 end{align})
    我们现在就可以用线段树维护这个序列了。线段树中的每个节点记录三个值(f_1,f_2,sum),表示该区间被加上了一个以(f_1,f_2)开头的数列,区间和为(sum)
    通过性质1,我们知道(f_1,f_2)可以叠加;
    通过性质2,我们可以(O(1))地将(f_1,f_2)下放;
    通过性质3,我们可以(O(1))地更新(sum)

    时间复杂度(O(mlogn))

    Code

    //DZY Loves Fibonacci Numbers
    #include <cstdio>
    inline char gc()
    {
        static char now[1<<16],*S,*T;
        if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
        return *S++;
    }
    inline int read()
    {
        int x=0,f=1; char ch=gc();
        while(ch<'0'||'9'<ch) {if(ch=='-') f=-1; ch=gc();}
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x*f;
    }
    typedef long long lint;
    int const N=3e5+10;
    lint const P=1e9+9;
    int n,m; lint F[N],a[N];
    #define s sg[s0]
    struct seg{lint f1,f2,sum;} sg[N*20];
    void update(int s0,int len)
    {
        s.f1%=P,s.f2%=P;
        s.sum=sg[s0<<1].sum+sg[s0<<1|1].sum+(s.f1*F[len]+s.f2*F[len+1]-s.f2),s.sum%=P;
    }
    void pushdown(int s0,int L0,int R0)
    {
        if(s.f1==0&&s.f2==0) return;
        int mid=L0+R0>>1,Ls0=s0<<1,Rs0=Ls0|1;
        sg[Ls0].f1+=s.f1; sg[Rs0].f1+=s.f1*F[mid-L0]+s.f2*F[mid-L0+1];
        sg[Ls0].f2+=s.f2; sg[Rs0].f2+=s.f1*F[mid-L0+1]+s.f2*F[mid-L0+2];
        s.f1=s.f2=0;
        update(Ls0,mid-L0+1); update(Rs0,R0-mid); 
    }
    void ins(int s0,int L0,int R0,int L,int R)
    {
        if(L<=L0&&R0<=R) {s.f1+=F[L0-L+1],s.f2+=F[L0-L+2],update(s0,R0-L0+1); return;}
        pushdown(s0,L0,R0);
        int mid=L0+R0>>1;
        if(L<=mid) ins(s0<<1,L0,mid,L,R);
        if(mid<R) ins(s0<<1|1,mid+1,R0,L,R);
        update(s0,R0-L0+1);
    }
    lint query(int s0,int L0,int R0,int L,int R)
    {
        if(L<=L0&&R0<=R) return s.sum;
        pushdown(s0,L0,R0);
        lint res=0; int mid=L0+R0>>1;
        if(L<=mid) res+=query(s0<<1,L0,mid,L,R);
        if(mid<R) res+=query(s0<<1|1,mid+1,R0,L,R);
        return res%P;
    }
    lint sumA[N];
    int main()
    {
        n=read(),m=read();
        F[1]=F[2]=1; for(int i=3;i<=n+1;i++) F[i]=(F[i-2]+F[i-1])%P;
        for(int i=1;i<=n;i++) a[i]=read(),sumA[i]=sumA[i-1]+a[i];
        int rt=1;
        for(int i=1;i<=m;i++)
        {
            int opt=read(),L=read(),R=read();
            if(opt==1) ins(rt,1,n,L,R);
            else printf("%lld
    ",(query(rt,1,n,L,R)+sumA[R]-sumA[L-1])%P);
        }
        return 0;
    }
    

    P.S.

    CF怎么是个题就要开long long!?
    不知道为什么要求对(10^9+9)取模,而不是(10^9+7)

  • 相关阅读:
    phonegap 捕获图片,音频,视屏 api capture
    phonegap的照相机 API
    phonegap 的指南针 api Compass
    PhoneGap Geolocation结合百度地图api获取地理位置api
    PhoneGap Geolocation 获取地理位置 api
    PhoneGap实现重力感应
    PhoneGap模仿微信摇一摇功能
    75-扩展GCD-时间复杂度
    15- 1 << k 时的益出
    6-画图
  • 原文地址:https://www.cnblogs.com/VisJiao/p/Cf446C.html
Copyright © 2020-2023  润新知