通过题目给的递推公式 可以的出其矩阵形式 然后就是求某一区间的矩阵乘积 线段树或者rmq都可以解
也可以只维护一个前缀积 然后求矩阵的逆
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define M 1000000007
struct node
{
int l;
int r;
ll mat[2][2];
};
node tree[400010];
ll res[2][2];
ll num[100010];
int n;
void mul(ll a[][2],ll b[][2],ll c[][2])
{
ll t[2][2];
int i,j,k;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
t[i][j]=0;
for(k=0;k<2;k++)
{
t[i][j]=(t[i][j]+(a[i][k]*b[k][j])%M)%M;
}
}
}
memcpy(c,t,sizeof(t));
return;
}
void pushup(int cur)
{
mul(tree[2*cur].mat,tree[2*cur+1].mat,tree[cur].mat);
return;
}
void build(int l,int r,int cur)
{
int m;
tree[cur].l=l;
tree[cur].r=r;
if(l==r)
{
tree[cur].mat[0][0]=0,tree[cur].mat[0][1]=num[l];
tree[cur].mat[1][0]=1,tree[cur].mat[1][1]=1;
return;
}
m=(l+r)/2;
build(l,m,2*cur);
build(m+1,r,2*cur+1);
pushup(cur);
return;
}
void query(int pl,int pr,int cur)
{
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
mul(res,tree[cur].mat,res);
return;
}
if(pl<=tree[2*cur].r) query(pl,pr,2*cur);
if(pr>=tree[2*cur+1].l) query(pl,pr,2*cur+1);
return;
}
int main()
{
ll ans;
int t,q,i,l,r;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++)
{
scanf("%lld",&num[i]);
}
build(1,n,1);
while(q--)
{
scanf("%d%d",&l,&r);
if(r-l==0)
{
printf("%lld\n",num[l]%M);
}
else if(r-l==1)
{
printf("%lld\n",num[r]%M);
}
else
{
res[0][0]=1,res[0][1]=0;
res[1][0]=0,res[1][1]=1;
query(l+2,r,1);
ans=((num[l]*res[0][1])%M+(num[l+1]*res[1][1])%M)%M;
printf("%lld\n",ans);
}
}
}
return 0;
}