转自:点击打开链接
题意:
给一个序列An
有m个询问,每个询问包括l和r
定义f(l) = a[l], f(l+1) = a[l+1], f(x)=f(x-1) + a[x] * f(x-2), x >= l + 2;
对每个询问,求f(r);
当x>=l+2时,
f(x)=f(x-1) + a[x]* f(x-2), 所以就有递推式
所以当r>=l+1时,
然后就可以先求出:
用线段树就可以在O(logn)的时间求出这个式子,不过线段树的每个节点保存的是一个矩阵
还有就是要注意矩阵乘的方向
总的复杂度是O(nlogn+mlogn)
WA注意用long long
AC代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MOD 1000000007
struct Matrix{
long long num[2][2];
Matrix( int n ){
num[0][0] = 1;
num[0][1] = n;
num[1][0] = 1;
num[1][1] = 0;
}
Matrix(){
memset( num, 0, sizeof( num ) );
}
Matrix operator*( const Matrix &b ) const{
Matrix mm;
for( int i = 0; i < 2; i++ ){
for( int j = 0; j < 2; j++ ){
mm.num[i][j] = 0;
for( int k = 0; k < 2; k++ ){
mm.num[i][j] = ( mm.num[i][j] + ( num[i][k] % MOD ) * ( b.num[k][j] % MOD ) ) % MOD;
}
}
}
return mm;
}
};
Matrix m[400000];
long long num[110000];
int N, M;
int lc( int root ){
return 2 * root;
}
int rc( int root ){
return 2 * root + 1;
}
void updata( int root ){
m[root] = m[rc(root)] * m[lc(root)];
}
void built( int l, int r, int root ){
if( l == r ){
long long temp;
scanf( "%lld", &temp );
Matrix tt( temp );
m[root] = tt;
num[l] = temp;
return;
}
int mid = ( l + r ) / 2;
built( l, mid, lc( root ) );
built( mid + 1, r, rc( root ) );
updata( root );
}
Matrix query( int L, int R, int l, int r, int root ){
if( L <= l && R >= r ){
return m[root];
}
Matrix a, b;
int mid = ( l + r ) / 2;
if( L <= mid ) a = query( L, R, l, mid, lc( root ) );
if( R > mid ) b = query( L, R, mid + 1, r, rc( root ) );
if( L > mid ) return b;
if( R <= mid ) return a;
return b * a;
}
int main(){
int T;
cin >> T;
while( T-- ){
cin >> N >> M;
built( 1, N, 1 );
for( int i = 1; i <= M; i++ ){
int l, r;
scanf( "%d%d", &l, &r );
if( r - l <= 1 ){
cout << num[r] << endl;
}else{
Matrix mm = query( l + 2, r, 1, N, 1 );
cout << ( num[l] % MOD * mm.num[0][1] % MOD + num[l+1] % MOD * mm.num[0][0] % MOD ) % MOD << endl;;
}
}
}
return 0;
}