zoj3772Calculate the Function(矩阵+线段树)

链接

表达式类似于斐波那契 但是多了一个变量 不能用快速幂来解 不过可以用线段树进行维护 

对于每一个点够一个2*2的矩阵 

1 a[i]

1  0   这个矩阵应该不陌生 类似于构造斐波那契的那个数列 还是比较容易能想到的 

然后就用线段树进行维护 注意矩阵不满足交换律 在乘的时候要倒序。

  1 #include <iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<stdlib.h>
  6 #include<vector>
  7 #include<cmath>
  8 #include<queue>
  9 #include<set>
 10 using namespace std;
 11 #define N 100010
 12 #define LL long long
 13 #define INF 0xfffffff
 14 #define mod 1000000007
 15 const double eps = 1e-8;
 16 const double pi = acos(-1.0);
 17 const double inf = ~0u>>2;
 18 struct Mat
 19 {
 20     LL c[2][2];
 21 }s[N<<2];
 22 LL o[N];
 23 Mat operator * (Mat a,Mat b)
 24 {
 25     Mat c;
 26     memset(c.c,0,sizeof(c.c));
 27     int i,j,k;
 28     for(k =0 ; k < 2 ; k++)
 29     {
 30         for(i = 0 ; i < 2 ;i++)
 31         {
 32             if(a.c[i][k]==0) continue;//优化
 33             for(j = 0 ;j < 2 ;j++)
 34             {
 35                 if(b.c[k][j]==0) continue;//优化
 36                 c.c[i][j] = (c.c[i][j]+a.c[i][k]*b.c[k][j])%mod;
 37             }
 38         }
 39     }
 40     return c;
 41 }
 42 void up(int w)
 43 {
 44    s[w] = s[w<<1|1]*s[w<<1];
 45 }
 46 void build(int l,int r,int w)
 47 {
 48     if(l==r)
 49     {
 50         s[w].c[0][0] = s[w].c[1][0] = 1;
 51         s[w].c[0][1] = o[l];
 52         s[w].c[1][1] = 0;
 53         return ;
 54     }
 55     int m = (l+r)>>1;
 56     build(l,m,w<<1);
 57     build(m+1,r,w<<1|1);
 58     up(w);
 59 }
 60 Mat getsum(int a,int b,int l,int r,int w)
 61 {
 62     if(a<=l&&b>=r)
 63     {
 64         return s[w];
 65     }
 66     int m = (l+r)>>1,i,j;
 67     Mat c;
 68     for(i=0 ;i < 2 ; i++)
 69     {
 70         for(j = 0 ;j < 2 ; j++)
 71         {
 72             if(i==j)
 73             c.c[i][j] = 1;
 74             else
 75             c.c[i][j] = 0;
 76         }
 77     }
 78     if(b>m)
 79     c=c*getsum(a,b,m+1,r,w<<1|1);
 80     if(a<=m)
 81     c=c*getsum(a,b,l,m,w<<1);
 82     return c;
 83 
 84 }
 85 int main()
 86 {
 87     int i,n,m,t;
 88     cin>>t;
 89     while(t--)
 90     {
 91         scanf("%d%d",&n,&m);
 92         for(i = 1 ;i <= n; i++)
 93         scanf("%lld",&o[i]);
 94         build(1,n,1);
 95         while(m--)
 96         {
 97             int a,b;
 98             scanf("%d%d",&a,&b);
 99             if(b-a<=1)
100             {
101                 printf("%lld\n",o[b]%mod);
102                 continue;
103             }
104             Mat x;
105             x.c[0][0] = o[a+1];
106             x.c[1][0] = o[a];
107             x.c[0][1] = 1;x.c[1][1] = 0;
108             Mat y = getsum(a+2,b,1,n,1);
109             x = y*x;
110             printf("%lld\n",(x.c[0][0])%mod);
111         }
112     }
113     return 0;
114 }
View Code

 

转载于:https://www.cnblogs.com/shangyu/p/3649125.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值