JZOJ4724. 斐波那契

来源:互联网 发布:c语言编程的小游戏 编辑:程序博客网 时间:2024/06/05 11:41

题目大意

定义Fi表示斐波那契数列的第i项。
给定一个长度为n的序列a,和m个操作。操作有两种:

  • 1 L R修改操作,表示给ai,(LiR)加上FiL+1
  • 2 L R询问操作,表示询问Ri=Lai mod (1e9+9)的值

Data Constraint
n,m105

题解

引入一种算法——定期重构


定期重构

每次的修改操作我们不直接修改而是先将操作存起来,当已经储存了Size(一般取Size=n)个操作时,再进行修改(重构)。每次查询,先查询已经重构的数组,再遍历已经存储的操作,每个操作单独计算贡献。
非常好证明,时间复杂度是O(nn),运用定期重构可以很好地平衡修改与查询的时间复杂度。


注意到这题,我们的一个修改操作[L,R]可以做到O(1),具体来说:
Deli表示第i个元素修改后需要加的值,那么对[L,R]修改相当于:

  • DelL=DelL+1
  • DelR+1=DelR+1FRL+2
  • DelR+2=DelR+2FRL+1
  • i>1,Deli=Deli+Deli1+Deli2

这样一来修改就能做到O(1)了,但是询问还是O(n)的。所以我们可以用到上文提到的定期重构来平衡复杂度。问题完美解决。

时间复杂度:O(nn)

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>using namespace std ;#define N 100000 + 10typedef long long ll ;const int MO = 1e9 + 9 ;struct Note {    int l , r ;    Note ( int L = 0 , int R = 0 ) { l = L , r = R ; }} C[N] ;int F[N] , S[N] ;int a[N] , sum[N] , del[N] ;int n , m , top , Size ;void ReBuild() {    a[1] = (a[1] + del[1]) % MO ;    sum[1] = a[1] ;    for (int i = 2 ; i <= n ; i ++ ) {        del[i] = ((del[i] + del[i-1]) % MO + del[i-2]) % MO ;        a[i] = (a[i] + del[i]) % MO ;        sum[i] = (sum[i-1] + a[i]) % MO ;    }    memset( del , 0 , sizeof(del) ) ;}int main() {    scanf( "%d%d" , &n , &m ) ;    Size = sqrt(n) ;    for (int i = 1 ; i <= n ; i ++ ) {        scanf( "%d" , &a[i] ) ;        sum[i] = (sum[i-1] + a[i]) % MO ;    }    F[1] = F[2] = 1 ;    S[1] = 1 , S[2] = 2 ;    for (int i = 3 ; i <= n ; i ++ ) {        F[i] = (F[i-1] + F[i-2]) % MO ;        S[i] = (S[i-1] + F[i]) % MO ;    }    for (int i = 1 ; i <= m ; i ++ ) {        int op , L , R ;        scanf( "%d%d%d" , &op , &L , &R ) ;        if ( op == 1 ) {            C[++top] = Note( L , R ) ;            del[L] = (del[L] + 1) % MO ;            del[R+1] = (del[R+1] - F[R-L+2] + MO) % MO ;            del[R+2] = (del[R+2] - F[R-L+1] + MO) % MO ;            if ( top == Size ) {                ReBuild() ;                top = 0 ;            }        } else {            int ans = (sum[R] - sum[L-1] + MO) % MO ;            for (int i = 1 ; i <= top ; i ++ ) {                if ( C[i].r < L || C[i].l > R ) continue ;                if ( L >= C[i].l && R <= C[i].r ) ans = (ans + (S[R-C[i].l+1] - S[L-C[i].l] + MO) % MO) % MO ;                else if ( C[i].l >= L && C[i].r <= R ) ans = (ans + S[C[i].r-C[i].l+1]) % MO ;                else if ( C[i].l >= L ) ans = (ans + S[R-C[i].l+1]) % MO ;                else ans = (ans + (S[C[i].r-C[i].l+1] - S[L-C[i].l] + MO) % MO) % MO ;            }            printf( "%d\n" , ans ) ;        }    }    return 0 ;}

以上.

2 0
原创粉丝点击