首页 > 代码库 > zoj3772【线段树+矩阵相乘】

zoj3772【线段树+矩阵相乘】

 

Calculate the Function

Time Limit: 2 Seconds      Memory Limit: 65536 KB

You are given a list of numbers A1 A2 .. AN and M queries. For the i-th query:

 

  • The query has two parameters Li and Ri.
  • The query will define a function Fi(x) on the domain [Li, Ri] ∈ Z.
  • Fi(Li) = ALi
  • Fi(Li + 1) = A(Li + 1)
  • for all x >= Li + 2Fi(x) = Fi(x - 1) + Fi(x - 2) × Ax

 

You task is to calculate Fi(Ri) for each query. Because the answer can be very large, you should output the remainder of the answer divided by 1000000007.

Input

There are multiple test cases. The first line of input is an integer T indicates the number of test cases. For each test case:

The first line contains two integers NM (1 <= NM <= 100000). The second line contains N integers A1 A2 .. AN (1 <= Ai <= 1000000000).

The next M lines, each line is a query with two integer parameters LiRi (1 <= Li <= Ri <= N).

Output

For each test case, output the remainder of the answer divided by 1000000007.

Sample Input

14 71 2 3 41 11 21 31 42 43 44 4

Sample Output

125131144

 题目大意很简单:就告诉你一个公式然后进行询问

分析:

这是昨天训练赛的题目

比赛的时候还没看

昨晚我以为是推公式进行求解

半天推出来的公式是错的TAT

其实我应该想到的

数据范围10^5若是公式的话不应该这么小的范围

这个的复杂度应该是一个nlog(n)的级别

后来周洲他们队结束之后a了

我打开第一眼

线段树

那时候脑袋里突然就想到了大概的方向

其实很简单的

F1, F2  可以推得 F2, F3

我们可以找到这么一个矩阵使其完成那个功能  

这个矩阵我得到的是

1      1

a[3]  0

 

那么继续往下推

就是继续乘以矩阵

1      1

a[3]  0

每次都乘会超时

那么我们用线段树在存储就可以了

每个节点存的是该节点下的矩阵的子矩阵的乘积

最后查询的时候只要把它和F1, F2相乘就可以了

 

代码:

 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5  6 const long long maxn = 100005; 7 const long long mod = 1000000007; 8 long long val[maxn]; 9 long long start[1][2];10 long long end[1][2];11 12 struct Node {13     long long b[2][2];14 };15 struct Tree {16     long long left, right;17     Node node;18 }tree[maxn << 2];19 20 Node mul(Node n1, Node n2) {21     Node n3;22     for(long long i = 0; i < 2; i++) {23         for(long long j = 0; j < 2; j++) {24             n3.b[i][j] = 0;25             for(long long k = 0; k < 2; k++) {26                 n3.b[i][j] += n1.b[i][k] * n2.b[k][j];27                 n3.b[i][j] %= mod;28             }29         }30     }31     return n3;32 }33 34 Node Build(long long root, long long left, long long right) {35     tree[root].left = left; tree[root].right = right;36     if(left == right) {37         tree[root].node.b[0][0] = 1; tree[root].node.b[0][1] = 1;38         tree[root].node.b[1][0] = val[left]; tree[root].node.b[1][1] = 0;39         return tree[root].node;40     }41     long long mid = ( left + right ) >> 1;42     return tree[root].node = mul(Build(root << 1, left, mid), Build(root << 1 | 1, mid + 1, right));43 }44 45 Node x;46 void init() {47     x.b[0][0] = 1; x.b[0][1] = 0;48     x.b[1][0] = 0; x.b[1][1] = 1;49 }50 51 Node cal(long long root, long long left, long long right) {52     if(tree[root].left > right || tree[root].right < left) {53         return x;54     }55     if(left <= tree[root].left && tree[root].right <= right) {56         return tree[root].node;57     }58     return mul(cal(root << 1, left, right), cal(root << 1 | 1, left, right) );59 }60 61 int main() {62     long long t, n, m;63     long long a, b;64     init();65     scanf("%lld",&t);66     while(t--) {67         scanf("%lld %lld",&n, &m);68         for(long long i = 1; i <= n; i++) {69             scanf("%lld",&val[i]);70         }71         Build(1, 1, n);72         while(m--) {73             scanf("%lld %lld",&a, &b);74             if(b <= a + 1) {75                 printf("%lld\n",val[b]);76                 continue;77             }78             start[0][0] = val[a + 1]; start[0][1] = val[a];79             Node mid = cal(1, a + 2, b);80             for(long long i = 0; i < 1; i++) {81                 for(long long j = 0; j < 2; j++) {82                     end[i][j] = 0;83                     for(long long k = 0; k < 2; k++) {84                         end[i][j] += start[i][k] * mid.b[k][j];85                         end[i][j] %= mod;86                     }87                 }88             }89             printf("%lld\n", end[0][0]);90         }91     }92     return 0;93 }
View Code

 

zoj3772【线段树+矩阵相乘】