题目描述
Chino非常注重自己的成绩
Chino有m种方式给自己增加rp以增加成绩,她的每种增加rp的方式都有n个阶段,第i种的第j个阶段增加的rp表示为Aij,表示连续进行了j天第i种增加rp的方式
Chino连续进行同一种方式,效果可能更好也可能更差,她想要知道在n天里能获得的最大rp,你能帮帮可爱的Chino吗?
输入输出格式
输入格式:
第一行,两个正整数n,m
接下来m行,第i+1行为n个整数A[i][1]~A[i][n]
输出格式:
一行一个数,最大的rp
输入输出样例
说明
本题分为3个Subtask
第一个Subtask,2组数据 ,保证n leq 50n≤50, m leq 5000m≤5000, a_i leq 1e9ai≤1e9
对于第二个Subtask,4组数据,保证n leq 70n≤70, m leq 10000m≤10000, a_i leq 1e9ai≤1e9
对于第三个Subtask,4组数据,保证n leq 100n≤100, m leq 5000m≤5000, a_i leq 1e9ai≤1e9
其中每组数据4分,对于每个Subtask及其中的每个数据点,取分数和。
样例解释1
第 1 天进行第 1 项活动,获得 A11=3 点rp。
第 2 天进行第 2 项活动,获得 A21=3 点rp。
第 3 天进行第 1 项活动,获得 A11=3 点rp。
样例解释2
第 1 天进行第 2 项活动,获得 A21=3 点rp。
第 2 天进行第 2 项活动,获得 A22=5 点rp(因为已经连续进行了 2 次第 2 项活动,因而是 A22 而不是 A21。
第 3 天进行第 3 项活动,获得 A31=4 点rp。
这个坑留了好久吧,终于回来填坑了
sol:
首先如果a = {3, 2, 1}, 如果取三天只能是6, 9是不合法的,这个要搞清楚
所以当前这个方案取了几天一定要有
f(i, j)表示到第i天,以第j中方案结尾的最大rp
g(i, j)记录当前这个方案取了几天
1、继续采用当前的方案
f(i,j)=f(i−1,j)+a[j][g(i−1,j)+1])
g(i,j)=g(i−1,j)+1
2、更换方案
f(i,j)=max(f(i−1,k)+a[j][1])(k!=j)
g(i,j)=1
然后这个k可以用前缀和处理掉,(滚存一下)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n, m, a[10005][105]; int f[105][10005], g[105][10005]; int pre[10005], suf[10005]; int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) scanf("%d", &a[i][j]); memset(f, 0, sizeof f); memset(g, 0, sizeof g); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if (f[i - 1][j] + a[j][g[i - 1][j] + 1] > max(pre[j - 1], suf[j + 1]) + a[j][1]) { f[i][j] = f[i - 1][j] + a[j][g[i - 1][j] + 1]; g[i][j] = g[i - 1][j] + 1; } else { f[i][j] = max(pre[j - 1], suf[j + 1]) + a[j][1]; g[i][j] = 1; } } memset(pre, 0, sizeof pre); memset(suf, 0, sizeof suf); for(int j = 1; j <= m; j++) pre[j] = max(pre[j - 1], f[i][j]); for(int j = m; j >= 1; j--) suf[j] = max(suf[j + 1], f[i][j]); } int ans = 0; for(int i = 1; i <= m; i++) ans = max(ans, f[n][i]); printf("%d ", ans); }