题目地址:http://codeforces.com/contest/1176/problem/F
思路:其实就是一个01背包问题,只是添加了回合和每回合的01限制,和每当已用牌数到了10的倍数,那张卡会触发double攻击。
因为卡使用的多少会触发double效果,所以我们要记录攻击的同时记录卡的使用次数,可以由01背包dp[N][N]改变,
第一个维度是当前是第几个回合,第二个维度是记录卡在用了n张的情况下造成的攻击力,但是dp[N][N](N <= 2e5),
占用内存太大显然不行。于是想到用dp[N][10]。
(因为卡的数量可能很多,我们其实只要记录最多三张1费,一张2费,一张3费)
每个回合用卡情况最多3种:
1.用3张一费卡。
2.用2张一费卡,或者1张一费卡,1张二费卡
3.用1张一费卡,或者1张二费卡,或者1张三费卡
1 #include<iostream>
2 #include<algorithm>
3 using namespace std;
4 #define rep(i,j,k) for(int i = (j); i <= (k); i++)
5 #define per(i,j,k) for(int i = (j); i >= (k); i--)
6 #define mod(x) ((x)%(MOD))
7
8 typedef long long LL;
9 const int MOD = 10;
10 const int N = 2e5 + 10;
11 LL dp[N + 2][10];
12
13 void init(){
14 rep(i, 0, N) rep(j, 0, 9) dp[i][j] = -1;
15 }
16
17 int main(){
18
19 ios::sync_with_stdio(false);
20 cin.tie(0);
21
22 init();
23
24 int n;
25 cin >> n;
26
27 dp[0][0] = 0;//初始化
28
29 rep(o, 1, n){
30 int num;
31 cin >> num;
32
33 int L1 = 0;
34 int L2 = 0;
35 int L3 = 0;
36 int c1[5] = { 0 };//费用1,记录v最大的三张
37 int c2 = 0;//费用2
38 int c3 = 0;//费用3
39
40 int c, v;
41 rep(i, 1, num){
42 cin >> c >> v;
43
44 if (c == 1){
45 if (L1 == 3){
46 int x = 1;
47 if (c1[x] > c1[2]) x = 2;
48 if (c1[x] > c1[3]) x = 3;
49 if (v > c1[x]) c1[x] = v;
50 }
51 else c1[++L1] = v;
52 }
53 else if (c == 2){
54 L2 = 1;
55 if (v > c2) c2 = v;
56 }
57 else if (c == 3){
58 L3 = 1;
59 if (v > c3) c3 = v;
60 }
61 }
62
63 sort(c1 + 1, c1 + 1 + 3);
64
65 int max_v = max(c1[3], max(c2, c3));//一张v最大的
66 int _2_1 = c1[3];//两张卡费用最大的
67 int _2_2 = c1[2];
68 if (c2 > _2_2) _2_2 = c2;
69 if (_2_2 > _2_1) swap(_2_2, _2_1);//两张卡,由1费中间v最大的2张,和一张2费的中间选出v最大的两张
70 LL _3 = c1[1] + c1[2] + c1[3];//用三张1费
71
72 rep(i, 0, 9) dp[o][i] = dp[o - 1][i];//先把上个回合的状态保存到当前回合,方便下边的比较
73 //因为这三种状态都是附加在上个状态下得出的,所以他们之间都是独立的。
74 //mod(i + x),(i + x >= 10)* value 用于判断是否满足大于等于用的次数是十张的倍数
75 rep(i, 0, 9){
76 if (dp[o - 1][i] != -1){//上个状态是存在的
77 if (L1 + L2 + L3 >= 1){//用的卡牌最少一张的时候,用一张情况
78
79 dp[o][mod(i + 1)] = max(dp[o][mod(i + 1)],
80 dp[o - 1][i] + max_v + (i + 1 >= 10)*max_v);
81
82 }
83 if (L2 + L1 >= 2){//1费2费用的卡牌至少有两张,用两张情况
84
85 dp[o][mod(i + 2)] = max(dp[o][mod(i + 2)],
86 dp[o - 1][i] + _2_1 + _2_2 + (i + 2 >= 10)*_2_1);
87
88 }
89 if (L1 >= 3){//1费卡牌数最少三张,用三张情况
90
91 dp[o][mod(i + 3)] = max(dp[o][mod(i + 3)],
92 dp[o - 1][i] + _3 + (i + 3 >= 10)*c1[3]);
93
94 }
95 }
96 }
97 }
98
99 LL ans = -1;
100
101 //rep(i, 0, n){
102 // rep(o, 0, 9) cout << dp[i][o] << " ";
103 // cout << endl;
104 //}
105 //cout << endl;
106
107 rep(o, 0, 9) ans = max(dp[n][o], ans);
108
109 cout << ans << endl;
110
111 return 0;
112 }