Gym 102056I - Misunderstood … Missing - [DP][The 2018 ICPC Asia-East Continent Final Problem I]

題目連接:https://codeforces.com/gym/102056/problem/Iios

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.c++

"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."app

Their conversation engaged Rikka. Feeling strange, she decided to follow them. But before all, she needs to beat the devil in her heart.ide

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?ui

Input
The first line contains a single integer $T (1 \le T \le 10)$, the number of test cases. Then $T$ test cases follow.spa

The input format of each test case is as follows:code

The first line contains a single integer $n (1 \le n \le 100)$, the number of rounds.orm

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;
    }
}
相關文章
相關標籤/搜索