替身使者 [区间dp]

替 身 使 者 替身使者 使


正 解 部 分 \color{red}{正解部分}

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

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

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

状态转移: F [ l , r ] = max ⁡ ( F [ l , k − 1 ] + F [ k + 1 , r ] + g ( c n t [ l , r , k ] ) ) F[l, r] = \max(F[l, k-1] + F[k+1, r] + g(cnt[l,r,k])) F[l,r]=max(F[l,k1]+F[k+1,r]+g(cnt[l,r,k]))

最后 a n s = F [ 1 , L e n ] ans = F[1, Len] ans=F[1,Len] .

其中 L e n Len Len 为将坐标离散化后的最大坐标 .


实 现 部 分 \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\n", DFS(1, Len));
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值