|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
const int N = 1e3 + 10;
|
|
|
|
|
|
/*
|
|
|
视频讲解
|
|
|
https://www.bilibili.com/video/BV1iT4y1U7tV/?spm_id_from=333.999.0.0
|
|
|
|
|
|
经验总结:
|
|
|
1、从样例入手,通过简单样例,思考人脑思维是如何一点点解决问题的。
|
|
|
2、在模拟样例的过程中,我们其实也是在秉承 多层循环,分别讨论的思路进行的思考。
|
|
|
3、在模拟样例的过程中,我们会发现有些地方是需要特判的,比如环形在1号与n号的交界处等情况,需要 road-=n
|
|
|
4、本题的题意是在任意时刻,你可以终止上一个机器人,它不用走完p个时长。
|
|
|
同时,下一个工厂也不一定非得是现在机器人停止的位置,可以是任意一个。这样自由度就很大,在代码中起到了降维的作用,否则
|
|
|
你就还需要考虑停止的位置,也就是下一个启动的工厂,是不是一定是前一个最大值的停止位,这样就不是一维的f[N]可以描述的了
|
|
|
最开始,我就是卡在这里,认为题解是错误的。
|
|
|
5、画图+样例梳理是解决问题的关键,先用人脑解决掉测试样例是非常重要的办法,然后再用代码模拟实现,再然后才是优化。
|
|
|
*/
|
|
|
int gold[N][N]; // gold[i][j]:第i条路,第j个时刻,可以获得的金币数量
|
|
|
int cost[N]; // cost[i]:在i个工厂购买机器人的花费
|
|
|
int n, m, p; // n个工厂,m个单位时间,p:机器人行走次数的上限
|
|
|
int f[N]; // f[i]:在前i个时间内,可以获得的最多金币数量
|
|
|
|
|
|
int main() {
|
|
|
cin >> n >> m >> p; // 工厂数量,最长的时长,机器人可以行走的次数上限
|
|
|
|
|
|
for (int i = 1; i <= n; i++) // n个工厂,比如2个工厂,其实有两条路径 ,就是1->2,2->1,工厂数量也就是路径数量
|
|
|
for (int j = 1; j <= m; j++) // m个时长
|
|
|
cin >> gold[i][j]; // 每段路径,在每个单位时间,可以获取到的金币数量
|
|
|
|
|
|
for (int i = 1; i <= n; i++) cin >> cost[i]; // 在每个工厂购买机器人需要花费的金币数量
|
|
|
|
|
|
// !!!!!!注意!!!!!!
|
|
|
// 有效状态初始化为负无穷,不能i=0开始,因为下面的代码中会依赖i=0,i=0时f[i]=0
|
|
|
for (int i = 1; i <= m; i++) f[i] = -1e9;
|
|
|
|
|
|
for (int i = 1; i <= m; i++) { // 枚举每个单位时间
|
|
|
for (int j = 1; j <= n; j++) { // 枚举每个工厂
|
|
|
int tmp = f[i - 1] - cost[j]; // 上一个时间单元的最大值,减去在j这个工厂购买机器人的花费金币数
|
|
|
for (int k = 0; k < p && i + k <= m; k++) {
|
|
|
int road = j + k; // 从j这个工厂开始,走k步(已减1),是哪个道路,比如:从1号工厂,走0步,就是1号道路
|
|
|
int time = i + k; // 到达了哪一时刻
|
|
|
if (road > n) road = road - n; // 环形
|
|
|
tmp += gold[road][time]; // 加上此道路,此时刻捡起来的金币数
|
|
|
f[time] = max(f[time], tmp); // 不断取最大值
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
// 输出
|
|
|
printf("%d\n", f[m]);
|
|
|
return 0;
|
|
|
}
|