Description

有一个大小为 的大方格,初始小人在位置 。记小人的位置为 ,每秒小人都能够移动至 的范围内。

给不定数个苹果,对苹果 , 在 时刻出现在, 下落速度为 , 价值为

  1. 求小人通过最优移动能够获得的最大价值和
  2. 打印小人每秒的移动策略

Solution

考虑

不难想到DP数组 的状态设置为小人在第 秒,位于位置 时获得的最大价值和。

是小人在第 秒,位于位置 时能够获得的价值和

由于起始位置固定,不妨倒过来DP。

答案就是

求DP的路径只需要记录是怎么转移的即可。

code
#include <bits/stdc++.h>
#define ull unsigned long long int 
//#define int long long int
#define endl '\n'
#define pb push_back
using namespace std;

const int N = 1E6 + 70,mod = 1e9 + 7,INF = 0x3f3f3f3f;

typedef pair<int,int> PII;

inline int read(){
    char ch = getchar();
    int x =0,f =1;
    for(;!isdigit(ch);ch =  getchar())
        if(ch == '-') f = -1;
    for(; isdigit(ch);ch = getchar())
        x = (x << 1) + (x << 3) + ch - '0';
    return f * x;
}

int pre[N][100];
int f[N][100];
int p[N][100];

/*
f[i][j] 表示为第 i 秒在位置 j 收集到的最大值。
p[i][j] 表示为刚好第 i 秒在位置 j 可以收集到的价值之和1

f[i][j] = max(f[i + 1][j-2 ~ j+2]) + p[i][j];
*/


void slove(){
    int n = read(),h = read();
    int t,x,v,w,maxt = 0;
    while(scanf("%d%d%d%d",&t,&x,&v,&w) != EOF){
        if((h - 1) % v)continue;
        int times = t + (h - 1) / v;
        p[times][x] += w;
        maxt = max(maxt,times);
    }
    int star =(n + 1) /2;
    for(int i = maxt;~i;i--){
        for(int j = 1;j <= n; j++){
            if(j - 2 >= 1 && f[i][j] < f[i + 1][j - 2] + p[i][j]){//这坨有点丑哈
                pre[i][j] = -2;
                f[i][j] = f[i + 1][j - 2] + p[i][j];
            }
            if(j  - 1 >= 1 && f[i][j] < f[i + 1][j - 1] + p[i][j]){
                pre[i][j] = -1;
                f[i][j] = f[i + 1][j - 1] + p[i][j];
            }
            if(f[i][j] < f[i + 1][j] + p[i][j]){
                pre[i][j] = 0;
                f[i][j] = f[i + 1][j] + p[i][j];
            }
            if(j + 1 <= n && f[i][j] < f[i + 1][j + 1] + p[i][j]){
                pre[i][j] = 1;
                f[i][j] = f[i + 1][j + 1] + p[i][j];
            }
            if(j + 2 <= n && f[i][j] < f[i + 1][j + 2] + p[i][j]){
                pre[i][j] = 2;
                f[i][j] = f[i + 1][j + 2] + p[i][j];
            }
        }
    }

    cout << f[0][star] << endl;
    int i = 0;
    while (i < maxt){
        cout << pre[i][star] << endl;
        star += pre[i][star];
        i ++;
    }
}

signed main(){
    int T = 1;
    //T = read();
    while(T --){
        slove();
    }
    return 0;
}