• 51nod 1680区间求和 (dp+树状数组/线段树)


    不妨考虑已知一个区间[l,r]的k=1、k=2....k=r-l+1这些数的答案ans(只是这一个区间,不包含子区间)

    那么如果加入一个新的数字a[i](i = r+1)

    则新区间[l, i]的答案为ans + (c+1)*a[i] + s ,c为[l,r]中小于等于a[i]的数的个数,s为大于它的树的和

    接下来考虑一个区间组,区间组i表示的是以i为结尾的所有区间

    另dp[i]表示[1,i], [2,i] .... [i-1, i],[i, i]这些区间的答案和

    那么dp[i+1] = dp[i] + ∑(j*a[j])(if a[j] >= a[i]) + ∑k*a[i](if a[k] < a[i]) + i*a[i]

    这样的话,最后只需要把dp[1~n]加起来就构成了答案

    上面的值可以使用树状数组或者线段树维护

    这里还使用了hashmap来进行离散化

    (线段树日常卡常数,优化很久才过)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <ext/hash_map>
    #define pb push_back
    #define fi first
    #define se second
    #define mp make_pair
    using namespace std;
    using namespace __gnu_cxx;
    const int maxn = 1e6 + 100;
    typedef long long LL;
    typedef pair<int, int> PII;
    vector<int> V(maxn, 0);
    const int MOD = (1e9 + 7) + 0.5;
    hash_map <int, int> H;
    PII tree[maxn*4];
    PII v;
    int k, L, R;
    inline PII Add(PII a, PII b){
        return {(a.fi + b.fi)%MOD, (a.se + b.se)%MOD};
    }
    void Insert(int o, int l, int r){
        if(l == r){
            tree[o] = Add(tree[o], {v.fi, (LL)v.fi*v.se%MOD});
            return;
        }
        int mid = (l+r)>>1;
        if(k <= mid) Insert(o<<1, l, mid);
        else Insert((o<<1)+1, mid+1, r);
        tree[o] = Add(tree[o<<1], tree[(o<<1)+1]);
    }
    PII Query(int o, int l, int r){
        if(tree[o].fi == 0) return mp(0, 0);
        if(L <= l && r <= R){
            return tree[o];
        }
        int mid = (l+r)>>1;
        return Add((L <= mid ? Query(o*2, l, mid) : mp(0, 0)),
                   (R > mid ? Query(o*2+1, mid+1, r) : mp(0, 0)));
    }
    int a[maxn], A, B, C;
    int n;
    
    void I_AM_ANGRY(){
        for(int i = 2; i <= n; i++){
            a[i] = ((LL)a[i-1]*A + B)%C;
            V[i] = a[i];
        }
        /*
        for(int i = 2; i <= n; i += 2){
            a[i] = ((LL)a[i-1]*A + B)%C;
            a[i+1] = ((LL)a[i]*A + B)%C;
            V[i] = a[i];
            V[i+1] = a[i+1];
        }
        */
        /*
        for(int i = 2; i <= n; i += 4){
            a[i] = ((LL)a[i-1]*A + B)%C;
            a[i+1] = ((LL)a[i]*A + B)%C;
            a[i+2] = ((LL)a[i+1]*A + B)%C;
            a[i+3] = ((LL)a[i+2]*A + B)%C;
    
            V[i] = a[i];
            V[i+1] = a[i+1];
            V[i+2] = a[i+2];
            V[i+3] = a[i+3];
        }*/
        V[1] = a[1];
    }
    
    int main()
    {
        cin>>n>>a[1]>>A>>B>>C;
        I_AM_ANGRY();
        sort(V.begin(), V.end());
        int tot = 0;
        for(auto x : V) if(!H[x]) H[x] = ++tot;
        LL dp = a[1], ans = dp;
        int N = n; n = tot;
        v = {1, a[1]}; k = H[a[1]];
        Insert(1, 1, n);
        for(int i = 2; i <= N; i++){
            int t = H[a[i]];
            L = t; R = n;
            PII x = Query(1, 1, n);
            dp = (dp + x.se + (LL)(tree[1].fi - x.fi+i)*a[i])%MOD;
            v = {i, a[i]}; k = t;
            Insert(1, 1, n);
            ans += dp;
        }
        cout<<(ans%MOD + MOD)%MOD<<endl;
        return 0;
    }
  • 相关阅读:
    Linux--VSFTP服务搭建
    Linux--Smba服务搭建
    Linux--DHCP搭建
    编程语言的分类
    用户,组及权限
    linux常用基本命令整理小结
    数据结构之顺序表实现
    进程管理之system
    进程管理之wait和waitpid
    进程管理之fork函数
  • 原文地址:https://www.cnblogs.com/Saurus/p/6868376.html
Copyright © 2020-2023  润新知