zoukankan      html  css  js  c++  java
  • 替身使者 [区间dp]

    使替身使者


    color{red}{正解部分}

    g(x)g(x) 画在坐标系中, 可以观察到其增速是十分快的, 且可以证明若一个人可以走到人多的地方, 一定是要走到的 .

    F[l,r]F[l, r] 表示不能走出区间 [l,r][l, r] 的所有人对答案的 最大 贡献, 枚举聚集点 kk, 使得所有能走到 kk 的人全都走到 kk, 再设 cnt[l,r,k]cnt[l, r, k] 表示 [l,r][l, r] 内的人可以走到 kk 的人数,

    cnt[l,r,k]cnt[l, r, k] 可以通过枚举 ll rr, O(N)O(N) 枚举人, 通过 差分 实现 O(N3)O(N^3) 预处理,

    状态转移: F[l,r]=max(F[l,k1]+F[k+1,r]+g(cnt[l,r,k]))F[l, r] = max(F[l, k-1] + F[k+1, r] + g(cnt[l,r,k]))

    最后 ans=F[1,Len]ans = F[1, Len] .

    其中 LenLen 为将坐标离散化后的最大坐标 .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    typedef long long ll;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 505;
    
    int N;
    int M;
    int Len;
    int L[maxn];
    int R[maxn];
    int B[maxn];
    int xs[maxn];
    int cnt[maxn][maxn][maxn];
    
    ll g[maxn];
    ll F[maxn][maxn];
    
    ll DFS(int l, int r){
            if(F[l][r] != -1) return F[l][r];
            F[l][r] = 0;
            for(reg int i = l; i <= r; i ++)
                    F[l][r] = std::max(F[l][r], DFS(l, i-1) + DFS(i+1, r) + g[cnt[l][r][i]]);
            return F[l][r];
    }
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i <= 5; i ++) xs[i] = read();
            for(reg int i = 1; i <= N; i ++){
                    ll base = i;
                    for(reg int j = 1; j <= 5; j ++) g[i] += 1ll*base*xs[j], base *= i;
            } 
            for(reg int i = 1; i <= N; i ++) L[i] = B[++ Len] = read(), R[i] = B[++ Len] = read();
            std::sort(B+1, B+Len+1); Len = std::unique(B+1, B+Len+1) - B-1;
            for(reg int i = 1; i <= N; i ++)
                    L[i] = std::lower_bound(B+1, B+Len+1, L[i])-B, R[i] = std::lower_bound(B+1, B+Len+1, R[i])-B;
            for(reg int i = 1; i <= Len; i ++)
                    for(reg int j = i; j <= Len; j ++){
                            for(reg int k = 1; k <= N; k ++)
                                    if(i <= L[k] && R[k] <= j) cnt[i][j][L[k]] ++, cnt[i][j][R[k]+1] --;
                            for(reg int k = 2; k <= Len; k ++) cnt[i][j][k] += cnt[i][j][k-1];
                    }
            memset(F, -1, sizeof F);
            printf("%lld
    ", DFS(1, Len));
            return 0;
    }
    
  • 相关阅读:
    湘潭大学 Hurry Up 三分,求凹函数的最小值问题
    hdu 1166 线段树 单点修改 + 询问区间求和 (线段树模板)
    hdu 1166 树状数组(模板) 更改点值+求区间和
    getline
    poj 1873 The Fortified Forest 凸包+位运算枚举 world final 水题
    C# 代码操作XML(增、删、改)
    C# Socket服务端与客户端通信(包含大文件的断点传输)
    MD5 十六进制加密
    C# 面向对象——多态
    C# 面向对象——继承
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822416.html
Copyright © 2011-2022 走看看