Gym 102056I - Misunderstood … Missing - [DP][The 2018 ICPC Asia-East Continent Final Problem I]
题目链接:https://codeforces.com/gym/102056/problem/I
Warm sunshine, cool wind and a fine day, while the girl watching is pursuing in chaos. Rikka reached out her hand and got the garland on her head, finding LCR with the immortal smile. The dream ended up waking, but the doubts will never disappear. In the end, without knowing about LCR, Rikka was invited to Shuyuan Men, a street of Chinese traditional arts in Xi'an.
"Is it enough to use the stored wires?"
"No problem... Those leaders are only concerned about expanding EC Final for the school's and their 'achievements'. All chores are ours. It is fine to simply connect those wiring boards in the series for each row."
Their conversation engaged Rikka. Feeling strange, she decided to follow them. But before all, she needs to beat the devil in her heart.
Rikka has an aggressivity $A$ and an increment $D$ of it, which are both $0$ initially. There are $n$ rounds in total. For $i=1,2,…,n$, at the beginning of $i$-th round Rikka's aggressivity $A$ increases by the increment $D$, and then she can do one of the following:
Attack and cause a damage of $(A+a_i)$.
Use the Omnipotent Garland from LCR to increase the increment $D$ by $b_i$.
Use her Schwarz Sechs Prototype Mark II to increase the aggressivity $A$ by $c_i$.
Rikka wonders the maximal possible damage she could cause in total. Could you help her?
Input
The first line contains a single integer $T (1 \le T \le 10)$, the number of test cases. Then $T$ test cases follow.
The input format of each test case is as follows:
The first line contains a single integer $n (1 \le n \le 100)$, the number of rounds.
The following $n$ lines contain ${a_i},{b_i},{c_i}$ for $i=1,2,…,n$. The $i$-th line among them contains three integers $a_i,b_i,c_i (1 \le a_i,b_i,c_i \le 10^9)$ separated by spaces in order.
It is guaranteed that the sum of $n$ in all test cases is at most 100.
Output
Output T lines; each line contains one integer, the answer to that test case.
Example
input
3
2
3 1 2
3 1 2
3
3 1 2
3 1 2
3 1 2
5
3 1 2
3 1 2
3 1 2
3 1 2
3 1 2
output
6
10
24
题意:
打怪,有 $A$ 的攻击力,有 $D$ 的成长,初始均为 $0$,有 $n$ 轮。
同时有三个数组 $a[1:n], b[1:n], c[1:n]$。
对于每一轮:
首先,攻击力永久性成长 $A = A + D$;然后,在下面三个选择中选择一种行为:
①、发起进攻,产生 $A + a_i$ 的伤害。
②、增加成长 $D = D + b_i$。
③、永久性增加攻击力 $A = A + c_i$。
问产生最大总伤害为多少。
题解:
onsite的时候,正向DP想不出来,没考虑逆向的DP。
不妨先将 $dp[i]$ 所表达的状态是从第 $i$ 轮开始进行攻击,到 $n$ 轮结束,那么自然地,其所存储的值是产生最大的伤害。
同时,假设 $dp[i+1]$ 已知,那么如果在第 $i+1$ 轮前面加一轮,不难计算第 $i$ 轮的三种选择产生的影响:
第 $i$ 轮选择①,则多产生 $a_i$ 的伤害。
第 $i$ 轮选择②,则成长增加了 $b_i$,假设其后在第 $j$ 轮进行一次攻击,则会多产生伤害 $(j-i) \cdot b_i$。
第 $i$ 轮选择③,则攻击力增加了 $c_i$,假设其后在第 $j$ 轮进行一次攻击,则会比原来产生的伤害增加 $c_i$。
不妨为 $dp[i]$ 再加两个状态:从第 $i$ 轮起,到第 $n$ 轮总共进行了 $cnt$ 次攻击;这 $cnt$ 次攻击的编号之和为 $sum$。
这样一来,上述第 $i$ 轮的三种选择,多产生的伤害分别为:$a_i$,$(sum-cnt \cdot i) \cdot b_i$ 和 $cnt \cdot c_i$。
总结一下,就是 $dp[i][cnt][sum]$ 代表:假设当前游戏是从第 $i$ 轮开始进行攻击的,到第 $n$ 轮结束,一共进行了 $cnt$ 次攻击,它们的轮编号之和为 $sum$,总共最大能产生多少伤害。
那么显然的,递推的起点就是 $dp[n][1][n] = a_n$;而 $dp[1][\cdots][\cdots]$ 中的最大值即为答案。
而状态转移可以如下进行倒推:
① $dp[i][cnt][sum] = max(dp[i][cnt][sum], dp[i+1][cnt-1][sum-i] + a_i )$
② $dp[i][cnt][sum] = max(dp[i][cnt][sum], dp[i+1][cnt][sum] + (sum-cnt \cdot i) \cdot b_i )$
③ $dp[i][cnt][sum] = max(dp[i][cnt][sum], dp[i+1][cnt][sum] + cnt \cdot c_i )$
然后,还有一个需要注意的点是,这样一来 $dp[i][cnt][sum]$ 的大小是 $100 \times 100 \times (1+\cdots+100)$,会MLE。需要进行滚动优化。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; int n; ll dp[2][105][5055]; ll a[105],b[105],c[105]; int main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int T; cin>>T; while(T--) { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]>>b[i]>>c[i]; memset(dp,0,sizeof(dp)); dp[n&1][1][n]=a[n]; for(int i=n-1;i>=1;i--) { for(int j=1;j<=n-i;j++) { int down=(i+i+j)*(j-1)/2+n, up=(n+n-j+1)*j/2; for(int k=down;k<=up;k++) { dp[i&1][j+1][k+i]=max(dp[i&1][j+1][k+i],dp[(i+1)&1][j][k]+a[i]); dp[i&1][j][k]=max(dp[i&1][j][k],dp[(i+1)&1][j][k]+j*c[i]); dp[i&1][j][k]=max(dp[i&1][j][k],dp[(i+1)&1][j][k]+(k-j*i)*b[i]); } } } ll ans=0; for(int j=1;j<=n;j++) for(int k=1;k<=5050;k++) ans=max(ans,dp[1][j][k]); cout<<ans<<endl; } }