题意:给出n个数,A1,A2....An,有m个操作,每个操作[L,R]令F(L)=AL,F(L+1)=AL+1,F(x)=F(x-1)+F(x-2)*Ax,对于每个查询,求F(R)。
思路:开始的时候各种推公式,结果根本推不出来啊,后来想用线段树强搞,发现和暴力貌似是一个复杂度的。。。后来还剩大概半个小时,想到了用矩阵乘法来表示操作,这个公式很容易写出矩阵,然后就预处理下前K项的矩阵的乘积,对于[L,R],要把前面的矩阵乘积"去掉",所以还要预处理下前面矩阵的逆的乘积,这里要注意一下矩阵乘的顺序,不然是没法消掉的。处理出来这两个东西以后就好弄了,对于查询,直接就能求出结果。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<set> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=100000+10; const int mod=1000000007; ll pow_mod(ll a,ll b) { ll ret=1; while(b) { if(b%2==1) ret=ret*a%mod; a=a*a%mod; b/=2; } return ret%mod; } struct Matrix { ll mat[2][2]; void clear(){memset(mat,0,sizeof(mat));} void init() {mat[0][0]=mat[1][1]=1;mat[1][0]=mat[0][1]=0;} void getA(ll A) { mat[0][0]=mat[0][1]=1;mat[1][0]=A;mat[1][1]=0;} void getAA(ll A) { mat[0][0]=0;mat[1][0]=1; mat[0][1]=pow_mod(A%mod,mod-2);mat[1][1]=-pow_mod(A,mod-2); mat[1][1]=mat[1][1]%mod+mod; } }; Matrix operator *(const Matrix &a,const Matrix &b) { Matrix c;c.clear(); for(int k=0;k<2;++k) for(int i=0;i<2;++i) for(int j=0;j<2;++j) c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod; return c; } Matrix mx[maxn],my[maxn]; int num[maxn],n; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t; int n,m; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&num[i]); Matrix x; mx[0].init();my[0].init(); for(int i=1;i<=n;++i) { x.getA(num[i]); mx[i]=mx[i-1]*x; x.getAA(num[i]); my[i]=x*my[i-1]; } int L,R; ll res; while(m--) { scanf("%d%d",&L,&R); if(R-L+1==1) res=num[L]; else if(R-L+1==2) res=num[R]; else { x=mx[R]; x=my[L+1]*x; res=num[L+1]*x.mat[0][0]%mod+num[L]*x.mat[1][0]%mod; res%=mod; } printf("%lld\n",res); } } return 0; }