• 洛谷 P3328 【[SDOI2015]音质检测】


    这题我做的好麻烦啊。。。

    一开始想分块来着,后来发现可以直接线段树

    首先考虑一个性质,我们如果有数列的相邻两项f[i]和 f[i+1]那么用这两项向后推k项其线性表示系数一定(表示为f[i+k]=a∗f[i]+b∗f[i+1]+c的形式),那么这样我们预处理这些系数,注意到维护的是一个乘积的形式,那么我们要维护这个必须得维护8个量,将其写成3 * 3矩阵的形式转移会比较科学,注意a=0的特判。

    说实话网上有些做法感觉很不科学啊。。。

    比如很多人初始化线段树的时候都暴力求的f函数,感觉不太科学啊。。。我的做法是BSGS预处理矩阵,这样查询单点就从33∗log变为33,不过我跑的好慢啊。。。还有就是标记下传的问题,网上竟然有下传是O(标记数)的做法,感觉和暴力没啥区别。

    复杂度:O(Qlogn∗34+Maxval−−−−−−−√∗33)

    上code:

    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cstdio>
    #include<cmath> 
    #define N 300002
    #define M 50002
    using namespace std;
    typedef long long LL;
    struct Mat
    {
        int g[3][3];
    };
    
    const int P = 1e9 + 7;
    int n,Q,a,b,A[N][4],inva,tag[N << 2],B;
    Mat Seg[N << 2];
        inline void in(int &x)
        {
            char c;
            while (!isdigit(c = getchar()));
            x = (c ^ 48);
            while (isdigit(c = getchar())) x = 10 * x + (c ^ 48);
        }
    
        inline void inc(int &x,int y)
        {
            x += y;
            if (x >= P) x -= P;
        }
    
    inline void init()
    {
        in(n); in(Q);
        in(a); in(b);
        a %= P; b %= P;
        for (int i = 1;i <= n; ++i)
            in(A[i][2]);
    }
    
            int coe[M][3],recoe[M][3];
                inline int quick(int x,int y)
                {
                    int res = 1,base = x;
                    for (;y;y >>= 1)
                    {
                        if (y & 1) res = 1LL * base * res % P;
                        base = 1LL * base * base % P;
                    }
                    return res;
                }
                    inline void Special()
                    {
                        for (int i = 3;i < M - 1; ++i)
                        {
                            recoe[i][0] = recoe[i - 1][0];
                            recoe[i][1] = recoe[i - 1][1];
                            recoe[i][2] = (recoe[i - 1][2] + P - b) % P;
                        }
                    }
            inline void Get_Coe()
            {
                inva = quick(a,P - 2); 
                coe[0][0] = 0; coe[0][1] = 0; coe[0][2] = 1;
                coe[1][0] = 0; coe[1][1] = 1; coe[1][2] = 0;
                coe[2][0] = 1; coe[2][1] = 0; coe[2][2] = 0;
                for (int i = 3;i < M - 1; ++i)
                {
                    coe[i][0] = (coe[i - 1][0] + 1LL * coe[i - 2][0] * a % P) % P;
                    coe[i][1] = (coe[i - 1][1] + 1LL * coe[i - 2][1] * a % P) % P;
                    coe[i][2] = ((coe[i - 1][2] + 1LL * coe[i - 2][2] * a % P) % P + b) % P;  
                }
                recoe[0][0] = 0; recoe[0][1] = 0; recoe[0][2] = 1;
                recoe[1][0] = 1; recoe[1][1] = 0; recoe[1][2] = 0;
                recoe[2][0] = 0; recoe[2][1] = 1; recoe[2][2] = 0;
                if (!a) 
                {
                    Special();
                    return;
                }
                for (int i = 3;i < M - 1; ++i)
                {
                    recoe[i][0] = 1LL * inva * (( -recoe[i - 1][0] + recoe[i - 2][0] + P) % P) % P;
                    recoe[i][1] = 1LL * inva * (( -recoe[i - 1][1] + recoe[i - 2][1] + P) % P) % P;
                    recoe[i][2] = 1LL * inva * ((( -recoe[i - 1][2] + recoe[i - 2][2] + P) % P + P - b) % P) % P;
                }
            }
                inline Mat mul(Mat x,Mat y)
                {
                    Mat c;
                    memset(c.g,0,sizeof(c.g));
                    for (int k = 0;k < 3; ++k)
                      for (int i = 0;i < 3; ++i)
                        for (int j = 0;j < 3; ++j)
                            if (x.g[i][k]&&y.g[k][j])
                                inc(c.g[i][j],1LL * x.g[i][k] * y.g[k][j] % P);
                    return c;
                }
    
                Mat Small[M],Big[M];
                    inline void Mat_init(Mat &x)
                    {
                        for (int i = 0;i < 3; ++i)
                            for (int j = 0;j < 3; ++j)
                                x.g[i][j] = (i == j);
                    }
    
                inline void BSGS()
                {
                    B = (int)(sqrt(2000000000)) + 5;
                    Mat now;
                    now.g[0][0] = 1; now.g[0][1] = 1; now.g[0][2] = 0;
                    now.g[1][0] = a; now.g[1][1] = 0; now.g[1][2] = 0;
                    now.g[2][0] = 1; now.g[2][1] = 0; now.g[2][2] = 1;
                    Mat_init(Small[0]);
                    for (int i = 1;i <= B; ++i)
                        Small[i] = mul(Small[i - 1],now);
                     now = Small[B];
                     Mat_init(Big[0]);
                     for (int i = 1;i <= B; ++i)
                        Big[i] = mul(Big[i - 1],now);
                }
    
                inline void update(int rt)
                {
                    for (int i = 0;i < 3; ++i)
                        for (int j = 0;j < 3; ++j)
                            Seg[rt].g[i][j] = (Seg[rt << 1].g[i][j] + Seg[rt << 1|1].g[i][j]) % P;
                }
    
                    Mat fu;
                        inline int add_Mul_it(int p,int q)
                        {
                            int S = 0;
                            for (int i = 0;i < 3; ++i)
                                for (int j = 0;j < 3; ++j)
                                    inc(S,1LL * coe[p][i] * coe[q][j] % P * fu.g[i][j] % P);
                            return S;
                        }
    
                        inline int dec_Mul_it(int p,int q)
                        {
                            int S = 0;
                            for (int i = 0;i < 3; ++i)
                                for (int j = 0;j < 3; ++j)
                                    inc(S,1LL * recoe[p][i] * recoe[q][j] % P * fu.g[i][j] % P);
                            return S;
                        }
    
                    inline void Deal(int l,int r,int rt,bool kind,int left,int right)
                    {
                        fu = Seg[rt];
                        memset(Seg[rt].g,0,sizeof(Seg[rt].g));
                        if (!kind)
                        {
                            for (int i = 0;i < 3; ++i)
                                for (int j = 0;j < 3; ++j)
                                {
                                    int p = (i == 2) ? 0 : (left + 2 - i),q = (j == 2) ? 0 : (right + 2 - j);
                                    Seg[rt].g[i][j] = add_Mul_it(p,q);
                                }
                            return;
                        }
                        for (int i = 0;i < 3; ++i)
                            for (int j = 0;j < 3; ++j)
                            {
                                int p = (i == 2) ? 0 : (left + i + 1),q = (j == 2) ? 0 : (right + j + 1);
                                Seg[rt].g[i][j] = dec_Mul_it(p,q);
                            }
                    }
    
                inline void pushdown(int l,int r,int rt)
                {
                    if (tag[rt])
                    {
                        int mid = (r + l) >> 1;
                        bool pd = (tag[rt] < 0);
                        int x = (tag[rt] > 0) ? tag[rt] : -tag[rt];
                        Deal(l,mid,rt << 1,pd,x,x);
                        Deal(mid + 1,r,rt << 1|1,pd,x,x);
                        tag[rt << 1] += tag[rt]; tag[rt << 1|1] += tag[rt];
                    }
                    tag[rt] = 0;
                }
    
            inline void build(int l,int r,int rt)
            {
                int mid = (r + l) >> 1;
                tag[rt] = 0;
                if (l == r)
                {
                    if (l == 1 || l == n) 
                    {
                        memset(Seg[rt].g,0,sizeof(Seg[rt].g));
                        return;
                    }
                    for (int i = 0;i < 3; ++i)
                        for (int j = 0;j < 3; ++j)
                        {
                            int p = (i == 2) ? 1 : A[l - 1][3 - i],q = (j == 2) ? 1 : A[l + 1][j ^ 1];
                            Seg[rt].g[i][j] = 1LL * p * q % P;
                        }
                    return;
                }
                build(l,mid,rt << 1);
                build(mid + 1,r,rt << 1|1);
                update(rt);
            }
    
            inline void change(int l,int r,int rt,int ll,int rr,bool kind,int left,int right)
            {
                int mid = (r + l) >> 1;
                if (ll <= l&&rr >= r)
                {
                    Deal(l,r,rt,kind,left,right);
                    (kind) ? --tag[rt] : ++tag[rt];
                    return;
                }
                pushdown(l,r,rt);
                if (ll <= mid) change(l,mid,rt << 1,ll,rr,kind,left,right);
                if (rr > mid) change(mid + 1,r,rt << 1|1,ll,rr,kind,left,right);
                update(rt);
            } 
    
            inline void change1(int l,int r,int rt,int pos,bool kind,int left,int right)
            {
                if (pos == 1||pos == n) return;
                int mid = (r + l) >> 1;
                if (l == r)
                {
                    Deal(l,r,rt,kind,left,right);
                    return;
                }
                pushdown(l,r,rt);
                if (pos <= mid) change1(l,mid,rt << 1,pos,kind,left,right);
                if (pos > mid) change1(mid + 1,r,rt << 1|1,pos,kind,left,right);
                update(rt);
            }
    
            inline int query(int l,int r,int rt,int ll,int rr)
            {
                if (ll > rr) return 0;
                int mid = (r + l) >> 1;
                if (ll <= l&&rr >= r)
                    return Seg[rt].g[0][0];
                pushdown(l,r,rt);
                int SS = 0;
                if (ll <= mid) inc(SS,query(l,mid,rt << 1,ll,rr));
                if (rr > mid) inc(SS,query(mid + 1,r,rt << 1|1,ll,rr));
                update(rt);
                return SS;
            }
    
                inline int Calc(int x)
                {
                    if (x <= 2) return x;
                    int p = (x - 2) / B,q = (x - 2) % B;
                    Mat c = mul(Big[p],Small[q]);
                    int Sum = 0;
                    inc(Sum,2LL * c.g[0][0] % P);
                    inc(Sum,c.g[1][0]);
                    inc(Sum,1LL * b * c.g[2][0] % P);
                    return Sum;
                }
        inline void PRE()
        {
            Get_Coe();
            BSGS();
            for (int i = 1;i <= n; ++i)
                A[i][0] = Calc(A[i][2] - 2),
                A[i][1] = Calc(A[i][2] - 1),
                A[i][3] = Calc(A[i][2] + 1),
                A[i][2] = Calc(A[i][2]);
            build(1,n,1);
        }
            int L,R;
            inline void Plus(bool pd)
            {
                if (R == L)
                {
                    if (L > 1) change1(1,n,1,L - 1,pd,0,1); 
                    if (R < n) change1(1,n,1,R + 1,pd,1,0);
                    return;
                }
                if (R - L > 1)
                    change(1,n,1,L + 1,R - 1,pd,1,1);
                change1(1,n,1,L,pd,0,1);
                if (L > 1) change1(1,n,1,L - 1,pd,0,1);
                change1(1,n,1,R,pd,1,0);
                if (R < n) change1(1,n,1,R + 1,pd,1,0);
            }
    
        inline void QUERY()
        {
            char ch[10];
            for (int i = 1;i <= Q; ++i)
            {
                scanf("%s",ch);
                in(L); in(R);
                if (ch[0] == 'p') Plus(0);
                if (ch[0] == 'm') Plus(1);
                if (ch[0] == 'q')
                    printf("%d
    ",query(1,n,1,L + 1,R - 1));
            }
        }
    
    inline void DO_IT()
    {
        PRE();
        QUERY();
    }
    
    int main()
    {
        init();
        DO_IT();
        return 0;
    }
    
    如果大家满意就关注我吧!
  • 相关阅读:
    C和C++内存模型
    makefile 学习归纳
    为知笔记给你更多
    二级指针探讨
    使用vscode书写博客
    C/C++ 笔试题一
    从一段经典错误代码说起——关于局部变量指针和函数传参的问题分析
    socket编程再分析(-)——基础
    samba服务器配置
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />详解
  • 原文地址:https://www.cnblogs.com/yihengblog/p/10123803.html
Copyright © 2020-2023  润新知