ZOJ 3772 Calculate the Function [线段树+矩阵乘法]【思维?】

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3772
————————————————————————————————————————————
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 + 2, Fi(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 N, M (1 <= N, M <= 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 Li, Ri (1 <= Li <= Ri <= N).

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

Sample Input
1
4 7
1 2 3 4
1 1
1 2
1 3
1 4
2 4
3 4
4 4

Sample Output
1
2
5
13
11
4
4
————————————————————————————————————————————
题目大意:

给一段序列 对于每一段查询区间,序列的值为
Fi(x)= ALiALi+1Fi(x1)+Fi(x2)×Axx=Lix=Li+1x>=Li+2

解题思路:

训练的时候一直想 会有什么技巧/黑科技一类的将其转化成一个O(1)查询的问题

最后还是没有想出来,最后看了题解 才知道这是一个线段树+矩阵乘法的

跟那个博主一样进入了 矩阵一定是求高次幂的误区

这题就是fibonacci数列
[ Fi(x+1)0Fi(x)0]×[ 1Ax+210]=[ Fi(x+2)0Fi(x+1)0]

我们只要用线段树处理出一段区间的右矩阵的乘积就好了

查询就变成了 O((log2(n)2)3)

附本题代码
———————————————————————————————————————————

#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;

const int N   = 100000+7;
const int M   = 2;
const int MOD = 1e9+7;

struct Matrix{
    LL m[M][M];
    void clear0(){
        for(int i=0;i<M;i++)
            for(int j=0;j<M;j++)
                m[i][j]=0;
    }
    void clearE(){
        for(int i=0;i<M;i++)
            for(int j=0;j<M;j++)
                m[i][j]=(i==j);
    }

};

Matrix operator * (Matrix a,Matrix b){
    Matrix c;
    c.clear0();

    for(int k=0;k<M;k++){
        for(int i=0;i<M;i++){
            for(int j=0;j<M;j++){
                c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j]+MOD)%MOD;
            }
        }
    }
    return c;
}

struct node{
    Matrix a;
    int l,r;
}tree[N<<2];
int w[N];

#define ll (rt<<1)
#define rr (rt<<1|1)
#define mid  ((r+l)>>1)

void pushup(int rt){
    tree[rt].a=tree[ll].a*tree[rr].a;
}

void build(int rt,int l,int r){
    tree[rt].l=l,tree[rt].r=r;
    if(l==r){
        tree[rt].a.m[0][0]=1   ,tree[rt].a.m[0][1]=1;
        tree[rt].a.m[1][0]=w[l],tree[rt].a.m[1][1]=0;
        return ;
    }
    build(ll,l,mid);
    build(rr,mid+1,r);
    pushup(rt);
}

Matrix query(int rt,int L,int R){
    if(L<=tree[rt].l&&tree[rt].r<=R)   return tree[rt].a;

    Matrix ans,b;ans.clearE();
    int md = (tree[rt].l+tree[rt].r)>>1;
    if(L<=md) b=query(ll,L,R),ans=ans*b;
    if(R> md) b=query(rr,L,R),ans=ans*b;
    return ans;
}

Matrix a,b;

void ask(int l,int r){
    if(l==r||l+1==r){
        printf("%d\n",w[r]);
        return ;
    }

    a.m[0][0]=w[l+1],a.m[0][1]=w[l];
    a.m[1][0]=0     ,a.m[1][1]=0;
    b=query(1,l+2,r);
    b=a*b;
    printf("%d\n",b.m[0][0]);

    return  ;
}

int main(){
    int _;
    scanf("%d",&_);
    while(_--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&w[i]);
        }

        build(1,1,n);

        int l,r;
        while(m--){
            scanf("%d%d",&l,&r);
            ask(l,r);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值