一.题目链接:
ZOJ-3772
二.题目大意:
给 n 个数 a[1~n]
定义 如下:
对于每次查询,给出区间端点 和 的值
求出 .
三.分析:
由递推式可得
所以我们可以建一颗线段树,节点值存为矩阵,父节点就存为矩阵乘积.
然后进行区间查询 即可.
查询得到的矩阵再乘以矩阵 取(0,0)元素即可.
因为线段树的遍历顺序,所以不必担心矩阵相乘的顺序会错误.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define pi acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)1e5;
const ll mod = 1000000007;
struct node1
{
ll D[2][2];
};
struct node2
{
int l;
int r;
node1 T;
}tree[M * 4 + 5];
ll a[M + 5];
node1 ans;
node1 juzhen(node1 s1, node1 s2)
{
node1 s3;
for(int i = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
s3.D[i][j] = 0;
for(int i = 0; i < 2; ++i)
{
for(int j = 0; j < 2; ++j)
{
for(int k = 0; k < 2; ++k)
{
s3.D[i][j] = (s3.D[i][j] + s1.D[i][k] * s2.D[k][j] % mod) % mod;
}
}
}
return s3;
}
void build(int k, int l, int r)
{
tree[k].l = l;
tree[k].r = r;
if(tree[k].l == tree[k].r)
{
tree[k].T.D[0][0] = 1;
tree[k].T.D[0][1] = 1;
tree[k].T.D[1][0] = a[tree[k].l];
tree[k].T.D[1][1] = 0;
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
build(k * 2, l, mid);
build(k * 2 + 1, mid + 1, r);
tree[k].T = juzhen(tree[k * 2].T, tree[k * 2 + 1].T);
}
void query(int k, int l, int r, int a, int b)
{
if(tree[k].l >= a && tree[k].r <= b)
{
ans = juzhen(ans, tree[k].T);
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
if(a <= mid)
query(k * 2, l, mid, a, b);
if(mid < b)
query(k * 2 + 1, mid + 1, r, a, b);
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%lld", &a[i]);
build(1, 1, n);
while((m--) > 0)
{
int l, r;
scanf("%d %d", &l, &r);
if(r - l < 2)
{
printf("%lld\n", a[r]);
continue;
}
ans.D[0][0] = 1;
ans.D[0][1] = 0;
ans.D[1][0] = 0;
ans.D[1][1] = 1;
query(1, 1, n, l + 2, r);
node1 s;
s.D[0][0] = a[l + 1];
s.D[0][1] = a[l];
s.D[1][0] = 0;
s.D[1][1] = 0;
ans = juzhen(s, ans);
printf("%lld\n", ans.D[0][0] % mod);
}
}
return 0;
}