【普及组】模拟赛C组 2109. 【普及模拟套题4】清兵线

mxy 沉迷于一个辣鸡游戏不可自拔。
在游戏中,杀死小兵是有一定的金钱奖赏的,小兵的价值等于它剩余血量。现在 mxy 与一列敌方小兵在同一直线上,我们用一个数轴表示,假设 mxy 在原点,现在有 n 个小兵,每个小兵总血量为 m,她们的位置分别在整点坐标 x1, x2, . . . , xn。现在它们处于一片密集的炮火区,因此,在每个单位时间内每个小兵都会掉一点血。mxy 的攻击很快,因此当她位于一个小兵面前的时候杀死小兵是不需要时间的,然后她会得到等于小兵被杀死前剩余血量的金钱数。mxy 在一个单位时间内只能移动一个单位长度。时间是宝贵的,mxy 想要马上知道对于这一列小兵,她一共能获得多少金钱奖赏。假设在整个清兵过程中,士兵是不会移动的。

 

老师说要帮学弟们做的题。

一道很简单的区间dp。设f[i][j][k][0/1]表示一共要杀k个小兵,选择杀i-j的小兵,此时最后一个杀的小兵是i/j时的答案。

用dfs转移,很简单就可以做出来,但是这样会空超,容易发现k这一维是可以省略的。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 310
using namespace std;
int n,m,i,j,f[N][N][2],x[N],ans;
void dfs(int l,int r,int num){
    if (f[l][r][0]>f[0][0][0]||f[l][r][1]>f[0][0][0]) return;
    if (l>r) return;
    dfs(l+1,r,num);dfs(l,r-1,num);
    //int sum=max(f[num][l+1][r][0]+m-(num-(r-l))*(x[l+1]-x[l]),f[num][l][r-1][1]+m-(num-(r-l))*(x[r]-x[r-1]));
    f[l][r][0]=f[l+1][r][0]+m-(num-(r-l))*(x[l+1]-x[l]);
    f[l][r][1]=f[l][r-1][1]+m-(num-(r-l))*(x[r]-x[r-1]);
    f[l][r][0]=max(f[l+1][r][1]+m-(num-(r-l))*(x[r]-x[l]),f[l][r][0]);
    f[l][r][1]=max(f[l][r-1][0]+m-(num-(r-l))*(x[r]-x[l]),f[l][r][1]);
    return;
}
int Abs(int x){
    if (x<0) return -x;
    return x;
}
int main(){
    freopen("kill.in","r",stdin);
    freopen("kill.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++)
        scanf("%d",&x[i]);
    sort(x+1,x+n+1);
    for (i=1;i<=n;i++){
        memset(f,128,sizeof(f));
        for (j=1;j<=n;j++)
            f[j][j][0]=f[j][j][1]=-Abs(x[j])*i+m;
        dfs(1,n,i);
        for (j=1;j<=n;j++)
            if (f[j][j+i-1][0]>ans) ans=f[j][j+i-1][0];
        for (j=1;j<=n;j++)
            if (f[j][j+i-1][1]>ans) ans=f[j][j+i-1][1];
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Mohogany/p/13774224.html