题目大意
定义Fibonacci数列为:$F[1]=1;~F[2]=1;~F[n]=F[n-1]+F[n-2]~(n>2)$
现有一个n个元素的数列$a$,进行m个操作,操作类型如下:
1 L R$~$表示给$a_i$加上$F[i-L+1]$,其中 L<=i<=R
2 L R$~$表示询问$\sum_{i=L}^Ra_i~mod~(10^9+9)$
1<=n, m<=10^5
【40%】n,m<=1000
$O(nm)$暴力
【100%解法1】n,m<=10^5
考虑平衡规划(定期重构),把修改操作储存起来,储到了$\sqrt{n}$个修改的时候更新原序列。
修改更新原序列:每个位置维护一个二元组$(x,y)$,$x$表示它前一个元素的增加量,$y$表示自己的增加量。对于第 j 个修改$L_j$~$R_j$,我们使$y_{L_j}+=1$,$x_{R_j+1}-=F[Len_j]$,$y_{R_j+1}-=F[Len_j+1]$。(这个类似于+1-1标记)。然后做一遍类似Fibonacci一样的循环:$x_i+=y_{i-1}$,$y_i+=x_{i-1}+y_{i-1}$。这样,我们就处理出了每个元素的增加量,最后$a_i+=y_i$。
询问:此时还剩下的修改操作在$\sqrt{n}$个以内,我们可以对剩下的每一个修改操作直接计算出对答案的贡献,最后加上原序列的前缀和即可。
时间复杂度$O(m\sqrt{n})$
【100%解法1.5】
解法1的修改我们维护的是一个二元组,其实每个位置维护一个值就行了。这算是个优化吧。
【100%解法2】
我们要知道这么些东西:
1、若$H_1=a$,$H_2=b$,$H_n=H_{n-1}+H_{n-2}$,则$H_n=aF_{n-2}+bF_{n-1}$。
2、推广一下,对于$H_1=a$、$H_2=b$的类Fibonacci数列,满足$\sum_{i=1}^nH_i=H_{n+2}-b$
因此我们只需知道数列的前两项就可以快速求和。
用线段树维护区间内的数列的前两项。
时间复杂度$O(m\log n)$
【100%解法3】
我们知道Fibonacci数列是有通项公式的。
科普:对于形如$F_n=pF_{n-1}+qF_{n-2}$的递推数列,令$x^2=px+q$,若该方程有两个不同的实数根$x_1$和$x_2$,则$F_n$的通项公式一定可以表示成$F_n=αx_1^n+βx_2^n$的形式
事实上,在本题的模意义下,$F[n]≡276601605*(691504013^n − 308495997^n)$。
于是任务变成维护两个等比数列。因为两个公比相同的等比数列可以直接相加,所以维护数列的首项即可。这个可以用线段树解决。
时间复杂度$O(m \log n)$
解法1代码
1 |
|
解法2代码来自LZH
1 |
|
参考资料:Johann写的题解
引用:lzh大神的代码