zoukankan      html  css  js  c++  java
  • Z0J 3772 Calculate the Function 线段树+矩阵

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5235

    这种题目居然没想到,一开始往矩阵快速幂想去了,因为之前跪了太多矩阵快速幂,后来就。。哎,擦。怎么没想到就是个线段树呢

    因为1 A[x]  *     A[x-1]  这个是很容易推出的,比赛的时候看到这个就想那个快速幂去了,根本没往线段树上想,其实用线段树存储前面的矩阵,得到一个询问

          1    0          A[x-2]

     L R,则访问 L+2 ,R的矩阵部分提取出来,再跟A[L] A[L+1]相乘就是结果了

    则建树为 nlogn,访问为mlogn,由于n和m都在10^5,所以可以承受

    要注意的是矩阵不满足交换律,在这个线段树里面矩阵相乘的时候必须从大的到小的来乘。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define lson rt<<1,l,mid
    #define rson (rt<<1|1),mid+1,r
    #define N 100010
    #define ll unsigned long long
    using namespace std;
    ll A[N],n,m;
    const ll M=1000000007;
    struct MAT
    {
       ll mat[4][4];
    }tree[N*3],E;
    void init(int rt,int x)
    {
        tree[rt].mat[0][0]=tree[rt].mat[1][0]=1;
        tree[rt].mat[0][1]=A[x];
        tree[rt].mat[1][1]=0;
    }
    MAT operator *(MAT a,MAT b)
    {
        MAT c;
        memset(c.mat,0,sizeof (c.mat));
        ll tmp;
        for (int i=0;i<2;i++)
        {
            for (int j=0;j<2;j++)
            {
                for (int k=0;k<2;k++)
                {
                    tmp=(a.mat[i][k]*b.mat[k][j])%M;
                    c.mat[i][j]+=tmp;
                    if (c.mat[i][j]>M)
                     c.mat[i][j]%=M;
                }
            }
        }
        return c;
    }
    void up(int l,int r,int rt)
    {
        tree[rt]=tree[rt<<1|1]*tree[rt<<1];
    }
    void build(int rt,int l,int r)
    {
        if (l>=r)
        {
            init(rt,l);
            return;
        }
        int mid=(l+r)/2;
        build(lson);
        build(rson);
        up(l,r,rt);
    }
    void test(int rt,int l,int r)
    {
            cout<<l<<" lr "<<r<<":"<<endl;
            for (int i=0;i<2;i++)
            {
                for (int j=0;j<2;j++)
                {
                    cout<<tree[rt].mat[i][j]<<" ";
                }
                cout<<endl;
            }
            cout<<endl;
    
        if (l>=r)
        {
          return;
        }
        int mid=(l+r)/2;
        test(lson);
        test(rson);
    }
    MAT query(int L,int R,int rt,int l,int r)
    {
        MAT c=E;
        if (L<=l && r<=R)
        {
            c=tree[rt];
            return c;
        }
        int mid=(l+r)/2;
        if (R>mid)
          c=query(L,R,rson);
        if (L<=mid)
          c=c*query(L,R,lson);
        return c;
    }
    int main()
    {
        int t,a,b;
        scanf("%d",&t);
        memset(E.mat,0,sizeof E.mat);
        E.mat[1][1]=E.mat[0][0]=1;
        while (t--)
        {
            scanf("%llu%llu",&n,&m);
            for (ll i=1;i<=n;i++)
              scanf("%llu",&A[i]);
    
            build(1,1,n);
            //test(1,1,n);
            for (ll i=0;i<m;i++)
            {
                scanf("%d%d",&a,&b);
                if (a>b) swap(a,b);
                if (b-a<=1)
                {
                    if (b==a)
                    printf("%llu
    ",A[a]);
                    else
                    printf("%llu
    ",A[b]);
                    continue;
                }
                MAT c;
                c=query(a+2,b,1,1,n);
                ll ans=((c.mat[0][0]*A[a+1])%M)+((c.mat[0][1]*A[a])%M);
                ans%=M;
                printf("%llu
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    [实变函数]4.4 依测度收敛
    [实变函数]4.3 可测函数的构造
    [实变函数]4.2 Egrov 定理
    [实变函数]4.1 可测函数 (measurable function) 及其性质
    [实变函数]4.0 引言
    [实变函数]3.3 可测集类
    垂直滚动选择效果的实现
    unity模型任意无限切割插件
    微信小程序—智能小蜜(基于智能语义解析olami开放平台)
    AdPlayBanner:功能丰富、一键式使用的图片轮播插件
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3650349.html
Copyright © 2011-2022 走看看