zoukankan      html  css  js  c++  java
  • ZOJ3772_Calculate the Function

    给出一些数组a[i],每次询问为li,ri,定义f[li]=a[li],f[li+1]=a[li+1],对于其他不超过ri的位置,f[x]=f[x-1]+a[x]*f[x-2] 。

    题目有着浓浓的矩阵气息。

    f[x]=f[x-1]+a[x]*f[x-2] 

    f[x-1]=f[x-1]+0

    根据上面两个我们就可以知道

    f[x]=========|1,a[x]|         f[x-1]

    f[x-1]=======|1 ,  0|         f[x-2]

    这样我们就把矩阵构造出来了,相当于每次询问某一段区间的矩阵的乘积。

    由于是连续的区间,线段树即可解决问题。

    注意矩阵是放在左边,所以大的位置放在左边,线段树操作的时候也需要注意了。

    召唤代码君:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define maxn 300300
    #define mod 1000000007
    typedef long long ll;
    using namespace std;
    
    class Mat{
    public:
        ll f[2][2];
        Mat() { f[0][0]=f[1][1]=f[0][1]=f[1][0]=0; }
        Mat(int f1,int f2,int f3,int f4){
            f[0][0]=f1,f[0][1]=f2,f[1][0]=f3,f[1][1]=f4;
        }
        Mat operator * (Mat m1) const{
            Mat m0;
            for (int i=0; i<2; i++)
                for (int j=0; j<2; j++)
                    for (int k=0; k<2; k++)
                        m0.f[i][j]=(m0.f[i][j]+f[i][k]*m1.f[k][j])%mod;
            return m0;
        }
        void output(){
            cout<<f[0][0]<<' '<<f[0][1]<<'
    '<<f[1][0]<<' '<<f[1][1]<<'
    ';
        }
    }tree[maxn];
    
    int n,m,T,a[maxn];
    
    void build(int rt,int l,int r)
    {
        if (l==r){
            tree[rt]=Mat(1,a[l],1,0);
            return;
        }
        int mid=(l+r)>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
        tree[rt]=tree[rt<<1|1]*tree[rt<<1];
    }
    
    Mat query(int rt,int l,int r,int L,int R)
    {
        if (L<=l && R>=r) return tree[rt];
        int mid=(l+r)>>1;
        Mat tot(1,0,0,1);
        if (R> mid) tot=query(rt<<1|1,mid+1,r,L,R);
        if (L<=mid) tot=tot*query(rt<<1,l,mid,L,R);
        return tot;
    }
    
    int main()
    {
        int x,y;
        scanf("%d",&T);
        while (T--)
        {
            scanf("%d%d",&n,&m);
            for (int i=1; i<=n; i++) scanf("%d",&a[i]);
            build(1,1,n);
            while (m--)
            {
                scanf("%d%d",&x,&y);
                if (y==x || y==x+1){
                    if (y==x) printf("%d
    ",a[x]);
                        else printf("%d
    ",a[x+1]);
                    continue;
                }
                Mat tmp=query(1,1,n,x+2,y);
                /*
                cout<<" ans Mat is : 
    ";
                tmp.output();
                cout<<" ...........   the end of Mat.";
                */
                printf("%d
    ",(int)((tmp.f[0][0]*a[x+1]+tmp.f[0][1]*a[x])%mod));
            }
        }
        return 0;
    }
  • 相关阅读:
    小知识点随手记
    [学习笔记]行列式
    集群心跳机制
    [学习笔记]整数划分数
    如何修改集群的公网信息(包括 VIP) (文档 ID 1674442.1)
    [学习笔记]二叉树的遍历
    Oracle RAC/Clusterware 多种心跳heartbeat机制介绍 RAC超时机制分析
    bzoj4671: 异或图——斯特林反演
    为Oracle Clusterware修改公用及私有网络接口
    [学习笔记]斯特林反演
  • 原文地址:https://www.cnblogs.com/lochan/p/3873730.html
Copyright © 2011-2022 走看看