Codeforces 1176F Destroy it!
题目链接
https://codeforces.com/contest/1176/problem/F
题目大意
有一个 $n$ 回合的游戏,每回合给你 $k$ 个花费和价值分别为 $c_i$ 和 $d_i$ 的卡牌。每回合可以以任意顺序使用总花费不超过 $3$ 的卡牌,每使用十张卡片,这第十张卡片的价值会翻倍。问最大的总价值是多少。
题目分析
对于所有的回合,定义 $f[i][j]$ 为进行到 $i$ 回合,使用了 $j$ 张卡的最大价值。那么需要考虑每一回合内的情况。对于每一回合,定义 $g[i][j][k][0/1]$ 为使用了前 $i$ 个卡牌,使用了 $j$ 张卡牌,共花费了 $k$,且有没有翻倍的卡的最大取值。显然这就是一个的背包问题,直接搞就可以。之后在考虑使用 $0$ 到 $3$ 张卡牌的情况对 $f$ 进行转移,注意一定要新加入的卡牌数和原来的卡牌数加起来超过 $10$ 的时候需要使用 $g[i][j][k][1]$ ,而其余情况需要使用 $g[i][j][k][0]$。最后取最大值即可。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <vector> using namespace std; const int maxn = 2e5 + 5; long long inf = 0x3f3f3f3f3f3f3f3f; int n, m, t; long long f[maxn][15]; long long g[maxn][5][5][2]; int read(){ int x; scanf("%d", &x); return x; } int main(){ int i, j, k, l, r; long long x, y; n = read(); for(i=0;i<=n;i++){ for(j=0;j<=10;j++){ f[i][j] = -inf; } } f[0][0] = 0; for(i=1;i<=n;i++){ m = read(); for(l=0;l<=3;l++){ for(r=0;r<=3;r++){ g[0][l][r][0] = g[0][l][r][1] = -inf; } } g[0][0][0][0] = 0; for(j=1;j<=m;j++){ x = read(); y = read(); for(l=0;l<=3;l++){ for(r=0;r<=3;r++){ g[j][l][r][0] = g[j - 1][l][r][0]; g[j][l][r][1] = g[j - 1][l][r][1]; } } for(l=0;l<=2;l++){ for(r=0;r<=3-x;r++){ g[j][l + 1][r + x][0] = max(g[j][l + 1][r + x][0], g[j - 1][l][r][0] + y); g[j][l + 1][r + x][1] = max(g[j][l + 1][r + x][1], max(g[j - 1][l][r][0] + 2 * y, g[j - 1][l][r][1] + y)); } } } for(j=0;j<10;j++){ for(k=0;k<=3;k++){ long long maxa = -inf; long long maxb = -inf; for(l=0;l<=3;l++){ maxa = max(maxa, g[m][k][l][0]); maxb = max(maxb, g[m][k][l][1]); } if(j + k >= 10){ f[i][(j + k) % 10] = max(f[i][(j + k) % 10], f[i - 1][j] + maxb); }else{ f[i][j + k] = max(f[i][j + k], f[i - 1][j] + maxa); } } } } long long ans = -inf; for(i=0;i<10;i++){ ans = max(ans, f[n][i]); } printf("%lld\n", ans); return 0; }