NC16590 [NOIP2010]乌龟棋
题目
题目描述
小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。
乌龟棋的棋盘是一行N 个格子,每个格子上一个分数(非负整数)。棋盘第1 格是唯一的起点,第N 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。
乌龟棋中M 张爬行卡片,分成4 种不同的类型(M 张卡片中不一定包含所有4 种类型的卡片见样例),每种类型的卡片上分别标有1、2、3、4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。
很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。
现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?
输入描述
第1行2个正整数N和M,分别表示棋盘格子数和爬行卡片数。第2行N个非负整数,\(a_1, a_2,\cdots , a_N\),其中ai表示棋盘第i个格子上的分数。
第3行M个整数,\(b_1,b_2, \cdots , b_M\) ,表示M张爬行卡片上的数字。
输入数据保证到达终点时刚好用光M张爬行卡片,即 \(N-1= \sum_{1}^Mb_i\)
输出描述
输出只有1行,1个整数,表示小明最多能得到的分数。
示例1
输入
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
输出
73
说明
小明使用爬行卡片顺序为1,1,3,1,2,得到的分数为6+10+14+8+18+17=73。注意,
由于起点是1,所以自动获得第1格的分数6。
示例2
输入
13 8
4 96 10 64 55 13 94 53 5 24 89 8 30
1 1 1 1 1 2 4 1
输出
455
备注
对于30%的数据有1≤N≤30,1≤M≤12。对于50%的数据有1≤N≤120,1≤M≤50,且4种爬行卡片,每种卡片的张数不会超过20。
对于100%的数据有1≤N≤350,1≤M≤120,且4种爬行卡片,每种卡片的张数不会超过40;
\(0≤a_i≤100,1≤i≤N\) ;\(1≤b_i≤4,1≤i≤M\) 。输入数据保证 \(N-1= \sum_{1}^Mb_i\)
题解
知识点:线性dp。
考虑 \(dp[i][j][k][l]\) 为第一、二、三、四种卡分别用了 \(i,j,k,l\) 张。显然有转移方程:
注意一下边界即可。
时间复杂度 \(O(N)\)
空间复杂度 \(O(M+N^4)\)
代码
#include <bits/stdc++.h>
using namespace std;
int a[357], b[10], dp[107][107][107][107];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
for (int i = 1;i <= n;i++) cin >> a[i];
for (int i = 1, tmp;i <= m;i++) cin >> tmp, b[tmp]++;
for (int i = 0;i <= b[1];i++) {
for (int j = 0;j <= b[2];j++) {
for (int k = 0;k <= b[3];k++) {
for (int l = 0;l <= b[4];l++) {
int d = i + j * 2 + k * 3 + l * 4 + 1;
dp[i][j][k][l] = max(
{
dp[max(0,i - 1)][j][k][l],
dp[i][max(0,j - 1)][k][l],
dp[i][j][max(0,k - 1)][l],
dp[i][j][k][max(0,l - 1)]
}
) + a[d];
}
}
}
}
cout << dp[b[1]][b[2]][b[3]][b[4]] << '\n';
return 0;
}
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16576438.html