• 选球游戏 题解———2019.10.19


    选球游戏( game )
    时间限制:3s
    空间限制:512MB
    编译时开启 O2 优化开关
    【问题描述】
    华华和秀秀在玩游戏。在他们面前有!个球排成一排,从左到右按 1 到!编号。每个球有一
    个可正可负的权值。 每一轮, 秀秀会选定一个区间[#,%], 将编号在这个区间内的所有球的权值
    加上一个值', 或者将编号在这个区间内的所有球的权值都设为其相反数。 华华则需从这!个球
    中选出(个球来,他的得分为这(个球的权值的乘积。
    华华每次都能快快地找出得分最优的选球方案来。秀秀想了想,决定提升游戏难度。她每
    次会选定一个区间[#,%],然后询问华华在这个区间内选出((1 ≤ ( ≤ 10)个球的所有方案的得
    分之和。
    这下可把华华难倒了,于是华华找到了聪明的你。你能帮帮他嘛?
    由于所有方案的得分之和可能很大,你只需要输出得分之和对1000000007(10 / + 7)取模
    的结果(负数请加上10 / + 7变成非负数)即可。
    【输入格式】
    从文件 game.in 中读入数据。
    输入第一行包含两个正整数!,1,分别表示球的个数和秀秀的操作条数。
    接下来一行包含!个空格隔开的整数,表示每个球初始的权值。
    接下来1行,每行表示秀秀的一个操作。
    若该行形如“1 # % '”,则表示秀秀将编号属于[#,%]的所有球的权值都加上了';
    若该行形如“2 # %”,则表示秀秀将编号属于[#,%]的所有球的权值都置为了其相反数;
    若该行形如“3 # % (”,则表示华华需要回答从[#,%]中选出(个球的所有取球方案的得分之
    和。
    【输出格式】
    输出文件到 game.out 中。
    对于秀秀宝宝的每一个询问操作,输出一行,表示该询问的答案。
    【样例输入】
    10 9
    3 6 7 4 6 1 6 7 2 6
    3 5 7 3
    1 1 7 -9
    1 2 3 5
    3 2 6 1
    2 5 8
    3 5 7 3
    2 2 3
    3 1 10 2
    3 1 2 2
    【样例输出】
    36
    999999996
    72
    999999885
    12
    【样例说明】
    第一个询问:6×1×6 = 36
    第二个询问:
    询问前各个球的权值为:-6 2 3 -5 -3 -8 -3 7 2 6
    2 + 3 + −5 + −3 + −8 = −1111 + (10 / + 7) = 999999996
    第三个询问:
    询问前各个球的权值为:-6 2 3 -5 3 8 3 7 2 6
    3×8×3 = 72

    考虑用线段树来完成此题。对于每个节点我们维护一个f[i](i in [1, 10]),表示这个节点所对应区间选i个球的答案。
    考虑如何合并两个节点lc,rc。f[i] = sum(lc.f[j] * rc.f[i-j]) j in [0,i]
    对于取相反数操作,只有当i是奇数时,才会改变f[i]的符号。
    对于一段区间+c的操作,设这段区间的长度为len,则新的f[i]为sum (f(j) * c^{i-j} * C(len - j, i - j)) jin [0,i] 其中C(n,m)表示n个数中选m个的组合数
    这样我们就可以套用区间修改区间询问的线段树来解决这道题了,时间复杂度为O(c^2nlogn)

    #include <cstdio>
    #include <cstdlib>
    #define MOD 1000000007
    #define N 100005
    typedef long long LL; 
    using namespace std;
    struct Node {
        LL f[11];
    }node[N * 4];
    LL a[N], lazy1[N * 4];
    bool lazy2[N * 4];
    LL C[N][11];
    
    Node merge(Node lc, Node rc) {
        Node o;
        o.f[0] = 1;
        for (int i = 1; i <= 10; i++) {
            o.f[i] = 0;
            for (int j = 0; j <= i; j++)
                o.f[i] = (o.f[i] + lc.f[j] * rc.f[i - j] % MOD) % MOD;
        }
        return o;
    }
    
    void build(int o, int l, int r) {
        if (l == r) {
            for (int i = 0; i <= 10; i++) node[o].f[i] = 0;
            node[o].f[0] = 1;
            node[o].f[1] = (a[l] % MOD + MOD) % MOD;
            return ;
        }
        int mid = (l + r) >> 1;
        build(o * 2, l, mid);
        build(o * 2 + 1, mid + 1, r);
        node[o] = merge(node[o * 2], node[o * 2 + 1]);
        return ;
    }
    
    void update1(int o, int l, int r, int c) {
        int len = r - l + 1;
        LL ff[11];
        for (int i = 0; i <= 10; i++) ff[i] = node[o].f[i];
        for (int i = 1; i <= 10; i++) {
            node[o].f[i] = 0;
            LL t = 1;
            for (int j = 0; j <= i; j++) {
                LL tmp = ff[i - j] * C[len - (i - j)][j] % MOD * t % MOD;
                node[o].f[i] = (node[o].f[i] + tmp) % MOD;
                t = t * c % MOD;
            }
        }
        return ;
    }
    
    void push_down(int o, int l, int r) {
        int mid = (l + r) >> 1;
        if (lazy1[o]) {
            if (lazy2[o * 2])
                lazy1[o * 2] = (lazy1[o * 2] + MOD - lazy1[o]) % MOD;
            else 
                lazy1[o * 2] = (lazy1[o * 2] + lazy1[o]) % MOD;
            if (lazy2[o * 2 + 1])
                lazy1[o * 2 + 1] = (lazy1[o * 2 + 1] + MOD - lazy1[o]) % MOD;
            else 
                lazy1[o * 2 + 1] = (lazy1[o * 2 + 1] + lazy1[o]) % MOD;
            update1(o * 2, l, mid, lazy1[o]);
            update1(o * 2 + 1, mid + 1, r, lazy1[o]);
            lazy1[o] = 0;
        }
        if (lazy2[o]) {
            lazy2[o * 2] ^= 1;
            lazy2[o * 2 + 1] ^= 1;
            for (int j = 1; j <= 10; j += 2) {
                node[o * 2].f[j] = MOD - node[o * 2].f[j];
                node[o * 2 + 1].f[j] = MOD - node[o * 2 + 1].f[j];
            }
            lazy2[o] = 0;
        }
    }
    
    void modify1(int o, int l, int r, int ll, int rr, int c) {
        if (ll <= l && rr >= r) {
            if (lazy2[o]) lazy1[o] = (lazy1[o] + MOD - c) % MOD;
            else lazy1[o] = (lazy1[o] + c) % MOD;
            update1(o, l, r, c);
            return ;
        }
        int mid = (l + r) >> 1;
        push_down(o, l, r);
        if (ll <= mid) modify1(o * 2, l, mid, ll, rr, c);
        if (rr > mid) modify1(o * 2 + 1, mid + 1, r, ll, rr, c);
        node[o] = merge(node[o * 2], node[o * 2 + 1]);
        return ;
    }
    
    void modify2(int o, int l, int r, int ll, int rr) {
        if (ll <= l && rr >= r) {
            for (int i = 1; i <= 10; i += 2) node[o].f[i] = MOD - node[o].f[i];
            lazy2[o] ^= 1;
            return ;
        }
        int mid = (l + r) >> 1;
        push_down(o, l, r);
        if (ll <= mid) modify2(o * 2, l, mid, ll, rr);
        if (rr > mid) modify2(o * 2 + 1, mid + 1, r, ll, rr);
        node[o] = merge(node[o * 2], node[o * 2 + 1]);
        return ;
    }
    
    Node query(int o, int l, int r, int ll, int rr) {
        if (ll <= l && rr >= r) 
            return node[o];
        int mid = (l + r) >> 1;
        push_down(o, l, r);
        if (rr <= mid) return query(o * 2, l, mid, ll, rr);
        if (ll > mid) return query(o * 2 + 1, mid + 1, r, ll, rr);
        Node lc = query(o * 2, l, mid, ll, rr);
        Node rc = query(o * 2 + 1, mid + 1, r, ll, rr);
        return merge(lc, rc);
    }
    
    int main(int argc, char ** argv) {
        // freopen("game.in", "r", stdin);
        // freopen("game.out", "w", stdout);
        int n, m;
        scanf("%d %d", &n, &m);
        C[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            C[i][0] = 1;
            for (int j = 1; j <= 10; j++) 
                C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
        }
        for (int i = 1; i <= n; i++) 
            scanf("%d", &a[i]);
        build(1, 1, n); 
        for (int i = 1; i <= m; i++) {
    
            int l, r, opt;
            scanf("%d%d%d",&opt, &l, &r);
            if (opt == 1) {
                int c;
                scanf("%d", &c);
                c = (c % MOD + MOD) % MOD;
                modify1(1, 1, n, l, r, c);
            }
            else if (opt == 2) {
                modify2(1, 1, n, l, r);
            }
            else {
                int k;
                scanf("%d", &k);
                Node o = query(1, 1, n, l, r);
                printf("%d
    ", o.f[k] % MOD);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    异步、作用域、闭包--setTimeout在for循环中的思考
    C++中*和&的定义和使用
    利用border设置transparent绘制图形
    暑假周记四
    暑假周记三
    win10系统下安装Linux虚拟机以及在虚拟机上安装Ubuntu
    暑假周记二
    暑假周记一
    《浪潮之巅》上——阅读笔记06
    《浪潮之巅》上——阅读笔记05
  • 原文地址:https://www.cnblogs.com/ydclyq/p/11705816.html
Copyright © 2020-2023  润新知