算法
(线性DP) $O(40^4)$
状态表示:$f[b_1, b_2, b_3, b_4]$ 表示所有第 $i$ 种卡片使用了 $b_i$ 张的走法的最大分值。
状态计算:将 $f[b_1, b_2, b_3, b_4]$ 表示的所有走法按最后一步选择哪张卡片分成四类:第 $i$ 类为最后一步选择第 $i$ 种卡片。比如 $i = 2$,则这一类的最大分值是 $f[b_1, b_2 - 1, b_3, b_4] + score[b_1 + 2b_2 + 3b_3 + 4b_4]$。
时间复杂度
一共有 $40^4$ 个状态,每个状态需要 $O(1)$ 的计算量,因此总时间复杂度是 $O(40^4)$。
C++ 代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 360, M = 41;
int n, m;
int score[N];
int f[M][M][M][M];
int main()
{
int b[5] = {0};
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%d", &score[i]);
for (int i = 0; i < m; i ++ )
{
int t;
scanf("%d", &t);
b[t] ++ ;
}
for (int A = 0; A <= b[1]; A ++ )
for (int B = 0; B <= b[2]; B ++ )
for (int C = 0; C <= b[3]; C ++ )
for (int D = 0; D <= b[4]; D ++ )
{
int t = score[A + B * 2 + C * 3 + D * 4];
int &v = f[A][B][C][D];
v = t;
if (A) v = max(v, f[A - 1][B][C][D] + t);
if (B) v = max(v, f[A][B - 1][C][D] + t);
if (C) v = max(v, f[A][B][C - 1][D] + t);
if (D) v = max(v, f[A][B][C][D - 1] + t);
}
printf("%d\n", f[b[1]][b[2]][b[3]][b[4]]);
return 0;
}
一开始开了五维,多了一位表示位置,但后来发现可以用走的棋数表示位置,感觉自己是真的蠢
是啊,我都想不到开几维
一开始在定义状态的时候是直观定义
f[N][M][M][M][M]
,爆内存,卡在了思考优化最后一维上。受y总每日一题讲解的启发,用short完成了最后一维的优化。现在的评测起貌似能过😄如果乌龟棋的步数不仅仅是1234,那又该怎么做⊙﹏⊙∥
那这题就只能暴搜吧.......,因为如果有M张的话,就要搜2的M次方,m不能太大就可以直接dfs搜就行
为什么A,B,C,D从0开始而不是1?
int t = score[A + B * 2 + C * 3 + D * 4];请问这一句中,score数组里面的这个含义是什么?还有下一行&v=f[a][b][c][d]这有什么用?
最后答案是不是少了 +score[0]??
神仙状态表示法,这没见过的,应该都想不出来
基础课 J2 +
提高课 S2 + / 省选 -
进阶课 省选+ / NOI / IOI/ ICPC/ 周赛++/yxc-
您好!这种状态数组是怎么想到的呢?是多做题,然后会碰到类似的!还是有什么好的策略呢?
多做题,就会碰到类似的。
状态表示怎么想到的,懵逼中qwq
y总,为什么M改为120就会RE啊?
可能是超出空间限制了
题目说每种卡片不会超过40张,空间限制最大64兆字节,当M=40时,40^4已经有两兆字节了,120肯定爆了
这里是不是还得考虑整形由4位字节存储呢?
状态计算不是很理解,y总。
比如说i = 2, 表示我此时的的选择步数为2的卡片,那么状态应该从f[b1,b2-1,b3,b4]转移过来,又因为此时我站在了[b1+2b2+3b3+4b4],所以还要加上score[b1+2b2+3b3+4b4]
对滴。
y总,dp这类问题的状态定义取决于什么。我总是拿到一个dp问题,不知道怎么定义它的状态。
感觉跟贪心一样有点玄学🤣
同感!!
不会写方程,不会设状态……
现在呢