• bzoj2962 序列操作


    2962: 序列操作

    Time Limit: 50 Sec  Memory Limit: 256 MB
    Submit: 1145  Solved: 378
    [Submit][Status][Discuss]

    Description

      有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c个数相乘的所有方案的和mod 19940417的值。

    Input

      第一行两个数n,q表示序列长度和操作个数。
      第二行n个非负整数,表示序列。
      接下来q行每行输入一个操作I a b c或者 R a b或者Q a b c意义如题目描述。

    Output

      对于每个询问,输出选出c个数相乘的所有方案的和mod19940417的值。

    Sample Input

    5 5
    1 2 3 4 5
    I 2 3 1
    Q 2 4 2
    R 1 5
    I 1 3 -1
    Q 1 5 1

    Sample Output

    40
    19940397
    样例说明
      做完第一个操作序列变为1 3 4 4 5。
      第一次询问结果为3*4+3*4+4*4=40。
      做完R操作变成-1 -3 -4 -4 -5。
      做完I操作变为-2 -4 -5 -4 -5。
      第二次询问结果为-2-4-5-4-5=-20。

    HINT

      100%的数据n<=50000,q<=50000,初始序列的元素的绝对值<=109,I a b c中保证[a,b]是一个合法区间,|c|<=109,R a b保证[a,b]是个合法的区间。Q a b c中保证[a,b]是个合法的区间1<=c<=min(b-a+1,20)。

    Source

    分析:线段树套路题.类似:传送门,这类题有一个特征就是需要维护的东西比较少:c <= 20,那么就可以开一个数组分别维护这些东西.
              f[i]表示当前区间选i个数相乘的和,显然一开始f[1] = a[pos].合并的时候f[i] = 左子树的f[i] + 右子树的f[i] + 左子树的f[j] * 右子树的f[k],j+k = i. 考虑两个修改操作对答案的影响.取反操作比较简单,注意到当i是奇数时f[i]才会变号.注意,取反以后一定要通过加上模数取模来变成正数.
              第一个操作有点鬼畜.纸上写几个例子,拆项后会再合并,就差不多能发现规律:,感性理解一下就是c的k次方,c要占k个位置,而另外的位置已经被f选的数给占了,只能在剩下的位置中选c,这大概就是组合数的意义.剩下的都可以通过合并同类项得到.
           一些细节需要注意,比如取反后一定要变成正数再来运算,f[0]一定要强制等于1,用类进行运算一定要先初始化,第一个操作对于f的处理要倒序处理,这些在之前附上链接的那道题中都有体现.
         总之,都是套路啦.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const ll maxn = 50010,mod = 19940417;
    ll n,q;
    ll a[maxn],c[maxn][21];
    
    struct node
    {
        ll add,cover,f[21],L,R;
        void init()
        {
            add = cover = L = R = 0;
            memset(f,0,sizeof(f));
            f[0] = 1;
        }
    } e[maxn << 2];
    
    node pushup(node a,node b)
    {
        node c;
        c.init();
        c.L = a.L;
        c.R = b.R;
        ll len1 = c.R - c.L + 1;
        ll len2 = a.R - a.L + 1;
        ll len3 = b.R - b.L + 1;
        for (ll i = 0; i <= min(len2,1LL * 20); i++)
            for (ll j = 0; j <= min(len3,1LL * 20); j++)
            {
                if (i + j > 20)
                    break;
                c.f[i + j] = (c.f[i + j] + a.f[i] * b.f[j] % mod) % mod;
            }
        c.f[0] = 1; //易错点
        return c;
    }
    
    void fan(ll o)
    {
        ll len = e[o].R - e[o].L + 1;
        for (ll i = 1; i <= min(len,1LL * 20); i++)
        {
            if (i % 2 == 1)
            {
                e[o].f[i] = -e[o].f[i];
                e[o].f[i] = (e[o].f[i] + mod) % mod;
            }
        }
        e[o].cover ^= 1;
        e[o].add = -e[o].add;
        e[o].add = (e[o].add + mod) % mod; //取反后一定要变成正数
    }
    
    void jia(ll o,ll v)
    {
        ll len = e[o].R - e[o].L + 1;
        for (ll i = min(len,1LL * 20);i >= 0; i--) //一定要倒着推
        {
            ll k = v;
            for (ll j = i - 1; j >= 0; j--)
            {
                e[o].f[i] = (e[o].f[i] + e[o].f[j] * c[len - j][i - j] % mod * k % mod) % mod;
                k = k * v % mod;
            }
        }
        e[o].add = (e[o].add + v) % mod;
    }
    
    void pushdown(ll o)
    {
        if (e[o].cover)
        {
            fan(o * 2);
            fan(o * 2 + 1);
            e[o].cover = 0;
        }
        if (e[o].add)
        {
            jia(o * 2,e[o].add);
            jia(o * 2 + 1,e[o].add);
            e[o].add = 0;
        }
    }
    
    void build(ll o,ll l,ll r)
    {
        e[o].init();
        e[o].L = l,e[o].R = r;
        if (l == r)
        {
            e[o].f[1] = a[l] % mod;
            return;
        }
        ll mid = (l + r) >> 1;
        build(o * 2,l,mid);
        build(o * 2 + 1,mid + 1,r);
        e[o] = pushup(e[o * 2],e[o * 2 + 1]);
    }
    
    void update1(ll o,ll l,ll r,ll x,ll y,ll v)
    {
        if (x <= l && r <= y)
        {
            jia(o,v);
            return;
        }
        pushdown(o);
        ll mid = (l + r) >> 1;
        if (x <= mid)
            update1(o * 2,l,mid,x,y,v);
        if (y > mid)
            update1(o * 2 + 1,mid + 1,r,x,y,v);
        e[o] = pushup(e[o * 2],e[o * 2 + 1]);
    }
    
    void update2(ll o,ll l,ll r,ll x,ll y)
    {
        if (x <= l && r <= y)
        {
            fan(o);
            return;
        }
        pushdown(o);
        ll mid = (l + r) >> 1;
        if (x <= mid)
            update2(o * 2,l,mid,x,y);
        if (y > mid)
            update2(o * 2 + 1,mid + 1,r,x,y);
        e[o] = pushup(e[o * 2],e[o * 2 + 1]);
    }
    
    node query(ll o,ll l,ll r,ll x,ll y)
    {
        if (x <= l && r <= y)
            return e[o];
        pushdown(o);
        ll mid = (l + r) >> 1;
        if (y <= mid)
            return query(o * 2,l,mid,x,y);
        else if (x > mid)
            return query(o * 2 + 1,mid + 1,r,x,y);
        else
            return pushup(query(o * 2,l,mid,x,mid),query(o * 2 + 1,mid + 1,r,mid + 1,y));
    }
    
    int main()
    {
        scanf("%lld%lld",&n,&q);
        c[0][0] = 1;
        for (ll i = 1; i <= n; i++)
        {
            c[i][0] = 1;
            for (ll j = 1; j <= 20; j++)
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
        }
        for (ll i = 1; i <= n; i++)
            scanf("%lld",&a[i]);
        build(1,1,n);
        while (q--)
        {
            char ch[2];
            ll a,b,c;
            scanf("%s",ch);
            if (ch[0] == 'I')
            {
                scanf("%lld%lld%lld",&a,&b,&c);
                update1(1,1,n,a,b,c);
            }
            if (ch[0] == 'R')
            {
                scanf("%lld%lld",&a,&b);
                update2(1,1,n,a,b);
            }
            if (ch[0] == 'Q')
            {
                scanf("%lld%lld%lld",&a,&b,&c);
                node temp = query(1,1,n,a,b);
                printf("%lld
    ",temp.f[c] % mod);
            }
        }
    
        return 0;
    }
  • 相关阅读:
    正则表达式去掉文件路径中的特殊字符
    用MD5加密字符串
    FTP响应码
    简述MD5校验文件
    SQLServer存储过程帮助类
    MySql数据库帮助类:DbHelperMySQL
    SQLServer数据库帮助类:DbHelperSQL
    基于Window10搭建android开发环境
    Ubuntu14.04搭建Android O编译环境
    Sublime text 3搭建Python开发环境及常用插件安装
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8432376.html
Copyright © 2020-2023  润新知