bzoj 4085: [Sdoi2015]音质检测

来源:互联网 发布:linux设置定时重启 编辑:程序博客网 时间:2024/04/28 23:45

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4085
思路:
这题我做的好麻烦啊。。。
一开始想分块来着,后来发现可以直接线段树
首先考虑一个性质,我们如果有数列的相邻两项f[i]f[i+1]那么用这两项向后推k项其线性表示系数一定(表示为f[i+k]=af[i]+bf[i+1]+c的形式),那么这样我们预处理这些系数,注意到维护的是一个乘积的形式,那么我们要维护这个必须得维护8个量,将其写成3 * 3矩阵的形式转移会比较科学,注意a=0的特判。
说实话网上有些做法感觉很不科学啊。。。
比如很多人初始化线段树的时候都暴力求的f函数,感觉不太科学啊。。。我的做法是BSGS预处理矩阵,这样查询单点就从33log变为33,不过我跑的好慢啊。。。还有就是标记下传的问题,网上竟然有下传是O(的做法,感觉和暴力没啥区别。
复杂度:O(Qlogn34+Maxval33)
代码:

#include<iostream>#include<cstring>#include<string>#include<cstdio>#include<cmath> #define N 300002#define M 50002using 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\n",query(1,n,1,L + 1,R - 1));        }    }inline void DO_IT(){    PRE();    QUERY();}int main(){    init();    DO_IT();    return 0;}
0 0