• 随机序列[SHOI2016](找规律+线段树)


    传送门

    这道题的题意就是给你n个数让你在每个数之间插入+、-、*三种运算符中的一种,然后算出一个答案,再把答案加起来。

    这题肯定是不能暴力的(题目都告诉你了由3n-1种结果)。我们先从小的情况枚举找一找规律。

    n=1

    a1

    n=2

    2*a1+a1*a2

    n=3

    6*a1+2*a1*a2+a1*a2*a3

    n=4

    18*a1+6*a1*a2+2a1*a2*a3+a1*a2*a3*a4

    发现没有?每一项是一个前缀积,每一项的系数除了最后两项都是后一项*3。这样我们就可以拿线段树维护这个答案了。

    每次改我们就在[k, n]这个区间*a[k]的逆*v(除a[k]乘v),在求一下[1, n]的和就是答案了。

    别忘了要把a[k]赋成v。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const ll N = 100010;
    const ll mod = 1000000007;
    ll n, Q;
    ll a[N], mul[N];
    struct Segment_Tree{
        ll val, tag;
    }st[N << 2];
    ll ksm(ll x, ll y) {
        ll ret = 1;
        while (y) {
            if (y & 1) ret = (ret * x) % mod;
            y >>= 1;
            x = (x * x) % mod;
        }
        return ret;
    }
    void build(ll x, ll l, ll r) {
        st[x].tag = 1;
        if (l == r) {
            if (l == n) {
                st[x].val = mul[n] % mod;
            } else if (l == n - 1) {
                st[x].val = (2 * mul[n - 1]) % mod;
            } else {
                st[x].val = (((ksm(3, n - l - 1) * 2) % mod) * mul[l]) % mod;
            }
            return;
        }
        ll mid = (l + r) >> 1;
        build(x << 1, l, mid);
        build(x << 1 | 1, mid + 1, r);
        st[x].val = (st[x << 1].val + st[x << 1 | 1].val) % mod;
    }
    void push_down(ll x) {
        if (st[x].tag != 1) {
            st[x << 1].tag = (st[x].tag * st[x << 1].tag) % mod;
            st[x << 1].val = (st[x].tag * st[x << 1].val) % mod;
            st[x << 1 | 1].tag = (st[x].tag * st[x << 1 | 1].tag) % mod;
            st[x << 1 | 1].val = (st[x].tag * st[x << 1 | 1].val) % mod;
            st[x].tag = 1;
        }
    }
    void change(ll x, ll l, ll r, ll p, ll q, ll v) {
        if (r < p || l > q) return;
        if (p <= l && r <= q) {
            st[x].tag = (st[x].tag * v) % mod;
            st[x].val = (st[x].val * v) % mod;;
            return;
        }
        push_down(x);
        ll mid = (l + r) >> 1;
        change(x << 1, l, mid, p, q, v);
        change(x << 1 | 1, mid + 1, r, p, q, v);
        st[x].val = (st[x << 1].val + st[x << 1 | 1].val) % mod;
    }
    ll read() {
        ll ret = 0, f = 1;
        char ch = getchar();
        while (!isdigit(ch)) {
            if (ch == '-') f = -1;
            ch = getchar();
        }
        while (isdigit(ch)) {
            ret = (ret << 1) + (ret << 3) + ch - '0';
            ch = getchar();
        }
        return ret * f;
    }
    int main() {
        mul[0] = 1;
        n = read(), Q = read();
        for (ll i = 1; i <= n; i++) {
            a[i] = read();
            mul[i] = (mul[i - 1] * a[i]) % mod;
        }
        build(1, 1, n);
        while (Q--) {
            ll t, v;
            t = read(), v = read();
            change(1, 1, n, t, n, (ksm(a[t], mod - 2) * v) % mod);
            cout << st[1].val << "
    ";
            a[t] = v;
        }
        return 0;
    }
  • 相关阅读:
    全选、全不选、反选
    IE Tester 怎样使用firebug 调试工具?
    策略模式
    模板方法模式
    迭代器模式——android中使用
    android 实现圆形波纹动画
    android 窗口的使用
    AlertDialog 基本使用
    国外android 网站
    ViewDragHelper 任意拖动
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12251986.html
Copyright © 2020-2023  润新知