替身使者 [区间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\n", DFS(1, Len));
        return 0;
}
posted @ 2019-10-23 22:04  XXX_Zbr  阅读(147)  评论(0编辑  收藏  举报