zoukankan      html  css  js  c++  java
  • 洛谷 P5608 [Ynoi2013] 文化课

    Chimuzu 手上有一个数字序列 ({a_{1},a_{2},ldots,a_{n}}) 和一个运算符序列 ({p_{1},p_{2},ldots,p_{n-1}})。其中 (p_{i}) 只能为 (+)( imes)

    我们定义一个区间 ([l,r]) 的权值 (w(l,r)) 为将字符串

    [a_{l}~p_{l}~a_{l+1}~p_{l+1} cdots a_{r-1}~p_{r-1}~a_{r} ]

    写下来之后,按照运算符的优先级计算出的结果。

    下面给出一个运算的例子:

    (a={1,3,5,7,9,11})(p={+, imes, imes,+, imes}),那么有:

    [w(1,6)=1+3 imes 5 imes 7+9 imes 11=205 ]

    [w(3,6)=5 imes 7+9 imes 11=134 ]

    Chimuzu 需要你对这两个序列进行修改,同时查询某个给定区间的权值。

    你需要维护这 (3) 个操作:

    操作一:给定 (l,r,x),将(a_{l},a_{l+1},ldots,a_{r}) 全部修改成 (x)

    操作二:给定 (l,r,y):将 (p_{l},p_{l+1},ldots,p_{r}) 全部修改成 (y)(0) 表示 (+)(1) 表示 ( imes)

    操作三:给定 (l,r):查询 (w(l,r) mod 1000000007) 的值。

    (n,mleq 100000)(1leq a_{i},xlt 2^{32})(a_{i},x) 均为奇数,(p_{i},yin{0,1})(1leq lleq rleq n),所有操作 (2) 还满足 (rlt n)。时限为 3s


    首先我们发现这个东西非常可以线段树维护,考虑合并两个区间 ([l,mid],[mid+1,r]) ,如果是加法就直接加起来;如果是乘法,收到乘法影响的只有左区间的一段后缀和右区间的一段前缀乘积,把这两段乘起来再加上剩下的贡献就是这个区间的答案。

    然后考虑区间修改符号,发现这个区间变成了区间和或者区间乘积,那么多维护一下区间和、乘积就可以了。

    最后是区间修改数,改完数之后这段区间的数都一样了,所以新的区间变成了若干个连乘段的和。而我们注意到 (1+2+3+dotssqrt{n}=n) ,所以本质不同的连乘段只有 (sqrt{len}) 个,于是我们记录每种长度为 (d_i) 段的个数 (ds_i) ,就可以直接计算 (sum_{i=1}^{cnt}ds_ix^{d_i}) 来更新答案,这样子复杂度是 (O(nsqrt{n})) 的。

    然后你会发现,要计算这个式子需要快速幂,而如果直接快速幂的话一定会使复杂度多一个 (log) ,而这题光速幂的空间开不下,所以我们考虑对 (d) 排好序之后 (x^i)(i-1) 快速幂过来,这样子复杂度会去掉这个 (log) ,我们来证明一下(这里分析上界)。

    现在我们有这个方程组:

    [egin{cases}sum_{i=1}^{cnt}x_i=n\sum_{i=1}^{cnt}log(x_i-x_{i-1})le O(sqrt{n})end{cases} ]

    (C_i=x_i-x_{i-1}) ,那么变成:

    [egin{cases}sum_{i=1}^{cnt}C_i imes i=n\sum_{i=1}^{cnt}log(C_i)le O(sqrt{n})end{cases} ]

    然后有:

    [egin{cases}sum_{i=1}^{cnt}C_i imes i=n\log(prod_{i=1}^{cnt}C_i)le O(sqrt{n})end{cases} ]

    (sum_{i=1}^{cnt}C_i imes i)取均值不等式有:

    [cnt!prod_{i=1}^{cnt}C_ile (frac{sum_{i=1}^{cnt}C_i imes i}{cnt})^{cnt}=(frac{n}{cnt})^{cnt} ]

    两边取 (log) 有:

    [log(prod_{i=1}^{cnt}C_i)le cntlog n -cntlog{cnt}-log(cnt!) ]

    因为斯特林近似有 (n!approxsqrt{2pi n}(frac{n}{e})^n) ,于是 (log(cnt!)=frac{1}{2}log {2pi}+frac{1}{2}log{cnt}+cntlog{cnt}-cnt) ,带回原式得:

    [log(prod_{i=1}^{cnt}C_i)le cntlog n-frac{1}{2}log {2pi}-frac{1}{2}log{cnt}-2cntlog{cnt}+cnt ]

    最大值也就是右式的最大值,舍掉部分小量和常数,那么就有一个 (y) 关于 (cnt) 的方程:

    [y=cntlog n-2cntlog{cnt}+cnt ]

    求导之后可以得到最大值是 (le sqrt{n}) 的,于是上面的结论得证。

    而至于有序,合并两个区间的时候归并就可以了。

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    const int N = 1e5;
    const int M = 317;
    const int p = 1e9 + 7;
    using namespace std;
    int a[N + 5],opt[N + 5],n,m,t[N + 5];
    vector <int>::iterator it;
    struct node
    {
        int sm,ans,mul,ls,rs,ll,rr,opt,lx,rx;
        vector <int> d,ds;
        void init(int x,int op)
        {
            sm = ans = mul = ls = rs = lx = rx = x;
            opt = op;
            ll = rr = 1;
        }
    };
    int mypow(int a,int x){int s = 1;for (;x;x & 1 ? s = 1ll * s * a % p : 0,a = 1ll * a * a % p,x >>= 1);return s;}
    struct Seg
    {
        node s[N * 4 + 5];
        int tag[N * 4 + 5],st[N * 4 + 5];
        #define zrt k << 1
        #define yrt k << 1 | 1
        void upd(node &s,node x,node y,int l,int mid,int r)
        {
            s.ll = x.ll;
            s.rr = y.rr;
            s.ls = x.ls;
            s.rs = y.rs;
            s.rx = y.rx;
            s.lx = x.lx;
            s.opt = y.opt;
            s.d.clear();
            s.ds.clear();
            if (x.opt)
            {
                s.ans = ((1ll * x.rs * y.ls % p + (x.ans - x.rs) % p) % p + (y.ans - y.ls) % p) % p;
                if (x.ll == mid - l + 1)
                    s.ls = 1ll * x.ls * y.ls % p,s.ll += y.ll;
                if (y.rr == r - mid)
                    s.rs = 1ll * y.rs * x.rs % p,s.rr += x.rr;
                s.sm = (x.sm + y.sm) % p;
                s.mul = 1ll * x.mul * y.mul % p;
            }
            else
            {
                s.ans = (x.ans + y.ans) % p;
                s.sm = (x.sm + y.sm) % p;
                s.mul = 1ll * x.mul * y.mul % p;
            }
            int j = 0,vis = (!x.opt),now = x.rr + y.ll;
            for (int i = 0;i < x.d.size();i++)
            {
                if (x.rr == x.d[i] && x.opt)
                {
                    x.ds[i]--;
                    if (!x.ds[i])
                        continue;
                }
                while (j < y.d.size())
                {
                    if (y.d[j] > x.d[i])
                        break;
                    if (y.ll == y.d[j] && x.opt)
                    {
                        y.ds[j]--;
                        if (!y.ds[j])
                        {
                            j++;
                            continue;
                        }
                    }
                    if (!vis && now <= y.d[j])
                    {
                        if (!s.d.size())
                            s.d.push_back(now),s.ds.push_back(1);
                        else
                            if (s.d[s.d.size() - 1] == now)
                                s.ds[s.d.size() - 1]++;
                            else
                                s.d.push_back(now),s.ds.push_back(1);
                        vis = 1;
                    }
                    if (!s.d.size())
                        s.d.push_back(y.d[j]),s.ds.push_back(y.ds[j]);
                    else
                        if (s.d[s.d.size() - 1] == y.d[j])
                            s.ds[s.d.size() - 1] += y.ds[j];
                        else
                            s.d.push_back(y.d[j]),s.ds.push_back(y.ds[j]);
                    j++;
                }
                if (!vis && now <= x.d[i])
                {
                    if (!s.d.size())
                        s.d.push_back(now),s.ds.push_back(1);
                    else
                        if (s.d[s.d.size() - 1] == now)
                            s.ds[s.d.size() - 1]++;
                        else
                            s.d.push_back(now),s.ds.push_back(1);
                    vis = 1;
                }
                if (!s.d.size())
                {
                    s.d.push_back(x.d[i]);
                    s.ds.push_back(x.ds[i]);
                }
                else
                    if (s.d[s.d.size() - 1] == x.d[i])
                        s.ds[s.d.size() - 1] += x.ds[i];
                    else
                        s.d.push_back(x.d[i]),s.ds.push_back(x.ds[i]);
            }
            while (j < y.d.size())
            {
                if (y.ll == y.d[j] && x.opt)
                {
                    y.ds[j]--;
                    if (!y.ds[j])
                    {
                        j++;
                        continue;
                    }
                }
                if (!vis && now <= y.d[j])
                {
                    if (!s.d.size())
                        s.d.push_back(now),s.ds.push_back(1);
                    else
                        if (s.d[s.d.size() - 1] == now)
                            s.ds[s.d.size() - 1]++;
                        else
                            s.d.push_back(now),s.ds.push_back(1);
                    vis = 1;
                }
                if (!s.d.size())
                    s.d.push_back(y.d[j]),s.ds.push_back(y.ds[j]);
                else
                    if (s.d[s.d.size() - 1] == y.d[j])
                        s.ds[s.d.size() - 1] += y.ds[j];
                    else
                        s.d.push_back(y.d[j]),s.ds.push_back(y.ds[j]);
                j++;
            }
            if (!vis)
                s.d.push_back(now),s.ds.push_back(1);
        }
        void upd2(node &s,node x,node y,int l,int mid,int r)
        {
            s.ll = x.ll;
            s.rr = y.rr;
            s.ls = x.ls;
            s.rs = y.rs;
            s.rx = y.rx;
            s.lx = x.lx;
            s.opt = y.opt;
            if (x.opt)
            {
                s.ans = ((1ll * x.rs * y.ls % p + (x.ans - x.rs) % p) % p + (y.ans - y.ls) % p) % p;
                if (x.ll == mid - l + 1)
                    s.ls = 1ll * x.ls * y.ls % p,s.ll += y.ll;
                if (y.rr == r - mid)
                    s.rs = 1ll * y.rs * x.rs % p,s.rr += x.rr;
                s.sm = (x.sm + y.sm) % p;
                s.mul = 1ll * x.mul * y.mul % p;
            }
            else
            {
                s.ans = (x.ans + y.ans) % p;
                s.sm = (x.sm + y.sm) % p;
                s.mul = 1ll * x.mul * y.mul % p;
            }
        }
        node upd1(node x,node y,int l,int mid,int r)
        {
            if (x.opt)
            {
                x.ans = ((1ll * x.rs * y.ls % p + (x.ans - x.rs) % p) % p + (y.ans - y.ls) % p) % p;
                if (x.ll == mid - l + 1)
                    x.ls = 1ll * x.ls * y.ls % p,x.ll += y.ll;
                if (y.rr == r - mid)
                    x.rs = 1ll * y.rs * x.rs % p,x.rr += y.rr;
                else
                    x.rs = y.rs,x.rr = y.rr;
                x.sm = (x.sm + y.sm) % p;
                x.mul = 1ll * x.mul * y.mul % p;
            }
            else
            {
                x.ans = (x.ans + y.ans) % p;
                x.sm = (x.sm + y.sm) % p;
                x.mul = 1ll * x.mul * y.mul % p;
                x.rs = y.rs;
                x.rr = y.rr;
            }
            x.rx = y.rx;
            x.opt = y.opt;
            return x;
        }
        void build(int k,int l,int r)
        {
            tag[k] = st[k] = -1;
            if (l == r)
            {
                s[k].init(a[l],opt[l]);
                s[k].d.push_back(1);
                s[k].ds.push_back(1);
                return;
            }
            int mid = l + r >> 1;
            build(zrt,l,mid);
            build(yrt,mid + 1,r);
            upd(s[k],s[zrt],s[yrt],l,mid,r);
        }
        void cha(int k,int l,int r,int z)
        {
            if (z == 0)
            {
                s[k].ans = s[k].sm;
                s[k].ls = s[k].lx;
                s[k].rs = s[k].rx;
                s[k].ll = s[k].rr = 1;
                s[k].d.clear();
                s[k].ds.clear();
                s[k].d.push_back(1);
                s[k].ds.push_back(r - l + 1);
            }
            else
            {
                s[k].ans = s[k].mul;
                s[k].ls = s[k].rs = s[k].mul;
                s[k].ll = s[k].rr = r - l + 1;
                s[k].d.clear();
                s[k].ds.clear();
                s[k].d.push_back(r - l + 1);
                s[k].ds.push_back(1);
            }
            tag[k] = z;
            s[k].opt = z;
        }
        void chan(int k,int l,int r,int z)
        {
            s[k].lx = s[k].rx = z;
            st[k] = z;
            int res = mypow(z,s[k].d[0]);
            s[k].ans = 1ll * s[k].ds[0] * res % p;
            for (int i = 1;i < s[k].d.size();i++)
            {
                res = 1ll * res * mypow(z,s[k].d[i] - s[k].d[i - 1]) % p;
                s[k].ans = (s[k].ans + 1ll * s[k].ds[i] * res % p) % p;
            }
            s[k].ls = mypow(z,s[k].ll);
            s[k].rs = mypow(z,s[k].rr);
            s[k].mul = mypow(z,r - l + 1);
            s[k].sm = 1ll * z * (r - l + 1) % p;
        }
        void pushdown(int k,int l,int r,int mid)
        {
            if (st[k] != -1)
            {
                chan(zrt,l,mid,st[k]);
                chan(yrt,mid + 1,r,st[k]);
                st[k] = -1;
            }
            if (tag[k] != -1)
            {
                cha(zrt,l,mid,tag[k]);
                cha(yrt,mid + 1,r,tag[k]);
                tag[k] = -1;
            }
        }    
        node query(int k,int l,int r,int x,int y)
        {
            if (l >= x && r <= y)
                return s[k];
            int mid = l + r >> 1;
            pushdown(k,l,r,mid);
            if (x > mid)
                return query(yrt,mid + 1,r,x,y);
            if (y <= mid)
                return query(zrt,l,mid,x,y);
            return upd1(query(zrt,l,mid,x,y),query(yrt,mid + 1,r,x,y),l,mid,r);
        }
        void modify1(int k,int l,int r,int x,int y,int z)
        {
            if (l >= x && r <= y)
            {
                cha(k,l,r,z);
                return;
            }
            int mid = l + r >> 1;
            pushdown(k,l,r,mid);
            if (x <= mid)
                modify1(zrt,l,mid,x,y,z);
            if (y > mid)
                modify1(yrt,mid + 1,r,x,y,z);
            upd(s[k],s[zrt],s[yrt],l,mid,r);
        }
        void modify2(int k,int l,int r,int x,int y,int z)
        {
            if (l >= x && r <= y)
            {
                chan(k,l,r,z);
                return;
            }
            int mid = l + r >> 1;
            pushdown(k,l,r,mid);
            if (x <= mid)
                modify2(zrt,l,mid,x,y,z);
            if (y > mid)
                modify2(yrt,mid + 1,r,x,y,z);
            upd2(s[k],s[zrt],s[yrt],l,mid,r);
        }
    }tree;
    inline long long read()
    {
    	long long X(0);int w(0);char ch(0);
    	while (!isdigit(ch)) w |= ch == '-',ch = getchar();
    	while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48),ch = getchar();
    	return w ? -X : X;
    }
    int main()
    {
        n = read();m = read();
        long long x;
        for (int i = 1;i <= n;i++)
        {
            x = read();
            a[i] = x % p;
        }
        for (int i = 1;i < n;i++)
            opt[i] = read();
        tree.build(1,1,n);
        int op,l,r;
        node ans;
        while (m--)
        {
            op = read();l = read();r = read();
            if (op == 3)
            {
                ans = tree.query(1,1,n,l,r);
                printf("%d
    ",(ans.ans + p) % p);
            }
            else
                if (op == 2)
                {
                    x = read();
                    tree.modify1(1,1,n,l,r,x);
                }
                else
                {
                    x = read();
                    x %= p;
                    tree.modify2(1,1,n,l,r,x);
                }
        }
        return 0;
    }
    
  • 相关阅读:
    12 go实现几中基本排序算法
    5 控制语句
    9 函数
    4. 常量与运算符
    AI
    AI
    AI
    AI
    ML
    ML
  • 原文地址:https://www.cnblogs.com/sdlang/p/14273835.html
Copyright © 2011-2022 走看看