• P6834 [Cnoi2020]梦原 树状数组 期望DP


    P6834 [Cnoi2020]梦原

    题目链接

    ​ 树状数组优化期望DP。

    ​ 我们可以发现,当(k= 1)时,这道题就和积木大赛一样,有一个非常有用的结论:对于每个点,只要把(max(0, a[i] - a[i - 1]))累加起来就是最终答案。假设前一个比后一个高,那么前一个为0时后一个一定早就为0了;假设后一个比前一个高,那么后一个多使用的操作就是后一个的高度减去前一个的高度。

    ​ 这个题把问题转化到了树上。因为(k)是不确定的,又因为要求期望,所以我们可以写出一个DP转移方程:(f[i] = displaystyle P(min(k, i - 1))sum _{j = i - k}^{i - 1} a[i] - a[j])。这个式子应该挺好理解,就是(E = displaystyle sum P *V)。因为每个(P)都一样,所以可以提出来。

    ​ 暴力算肯定是不行的,所以我们用树状数组维护一下。维护一个前缀和,再维护一个个数的前缀和,上式就可以化成(cnt * a[i] - sum a[j])

    #include <bits/stdc++.h>
    
    #define int long long
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 1e6 + 5, mod = 998244353;
    int n, k, ans;
    int a[N], b[N], c[N], t_num[N], t_sum[N];
    
    int lowbit(int x) { return x & -x; } 
    
    void change(int x, int sum, int num) { for(; x < N; x += lowbit(x)) t_sum[x] += sum, t_num[x] += num; }
    
    int query_sum(int x) { int res = 0; for(; x ; x -= lowbit(x)) (res += t_sum[x]) %= mod; return res; }
    
    int query_num(int x) { int res = 0; for(; x ; x -= lowbit(x)) (res += t_num[x]) %= mod; return res; }
    
    int ksm(int x, int y) {
        int res = 1;
        while(y) {
            if(y & 1) res = 1ll * res * x % mod;
            x = 1ll * x * x % mod; y >>= 1; 
        }
        return res;
    }
    
    int inv(int x) {
        return ksm(x, mod - 2);
    }
    
    signed main() {
    
        n = read(); k = read();
        for(int i = 1;i <= n; i++) b[i] = a[i] = c[i] = read();
        
        sort(b + 1, b + n + 1);
        int cnt = unique(b + 1, b + n + 1) - b - 1;
        for(int i = 1;i <= n; i++) a[i] = lower_bound(b + 1, b + cnt + 1, a[i]) - b; //离散化
    
        ans = c[1]; change(a[1], c[1], 1);
        for(int i = 2;i <= n; i++) {
            if(i >= k + 2) change(a[i - k - 1], -c[i - k - 1], -1); //不在范围内的减去
            (ans += 1ll * inv(i <= k + 1 ? i - 1 : k) * ( 1ll * query_num(a[i]) * c[i] % mod - query_sum(a[i])) % mod) %= mod; 
            (ans += mod) %= mod;
            change(a[i], c[i], 1);
        }
    
        printf("%lld", ans);
    
        return 0;
    }
    
    
  • 相关阅读:
    Mysql如何修改unique key
    centos 编译 安装 protobuf
    EasyNetQ简单使用
    微信发送模板消息
    Python删除开头空格
    代码积累-Common
    sql With(NoLock),With(ReadPast)
    webform 使用log4net配置
    log4net.dll添加报错
    js-小数计算问题
  • 原文地址:https://www.cnblogs.com/czhui666/p/13703559.html
Copyright © 2020-2023  润新知