2018 ICPC-EC Final I题【DP】

版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/86373994

题目描述 

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,…,ni=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+ai)(A+ai).
    ·Use the Omnipotent Garland from LCR to increase the increment D by bibi.
    ·Use her Schwarz Sechs Prototype Mark II to increase the aggressivity A by cici.

Rikka wonders the maximal possible damage she could cause in total. Could you help her?

输入描述:

The first line contains a single integer T (1≤T≤10)T (1≤T≤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≤n≤100)n (1≤n≤100), the number of rounds.
The following n lines contain {ai},{bi},{ci}{ai},{bi},{ci} for i=1,2,…,ni=1,2,…,n. The i-th line among them contains three integers ai,bi,ci (1≤ai,bi,ci≤109)ai,bi,ci (1≤ai,bi,ci≤109) separated by spaces in order.
It is guaranteed that the sum of n in all test cases is at most 100.

输出描述:

Output T lines; each line contains one integer, the answer to that test case.

示例1

输入

复制

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

输出

复制

6
10
24

  过去了快一个月了吧,这段时间的刷题怕是都快淡忘了那段打铁的心情了,那次的没能开出L题,让我们最后的努力都付诸东流,一道水题,却读错题意,于是就极度尴尬的打铁了,是幸也或许是不幸这是我的第一次ICPC/ACM之旅,却是两个带我的学长的额最后的一次比赛…… 

  趁着CF还在跑昨晚的div.2的比赛的时候,就写一下这一道DP,正巧是今天的牛客的重现赛,又重新打了一遍比上次,就是开出了一道DP以及一道几何,所谓银牌题和铜牌题。还行,算是有点进步了吧,最近也是开始集训了,第一周的动态规划进阶版本也的确够我们吃一段时间了,还加上补题…… 又是一套组合技!

  说一下上次出去比赛的I题,哎,主要是心态奔了,不然的话,和队友一起应该是可以推出来动态转移方程的。

  我们可以倒过来推这个DP,目的就是为了确保数据,因为最后一次操作一定是造成伤害的操作,所以,我们以末状态向前推来解这道题,假设这样的DP,dp[i][j][k]:【i】:第i位的状态,逆推(尽管比赛的时候题目给的是一个G的内存,可以直接上dp[100][100][5050],但是重现赛的时候,就是少了些内存,那么就写滚动数组,多加几次初始化所需要的时间之外,就是可以做到优化空间);【j】:表示的是到目前这位,打出了多少次伤害了,最早的时候,给dp[N][1][N] = a[i];因为最后一次是打出伤害的(不然血亏);【k】:在已经打出的j次伤害中,他们j次伤害的位置和,用来表示最后的状态,且一定是最优解,目的就是为了取的顺序最优。

  接下来就是怎么处理的问题了,知道如果不打出伤害,那么状态一定是这样的:

dp[i][j][k] = max( dp[i][j][k], dp[i+1][j][k] + max(j * c[i], (k - i * j) * b[i] ) );

  其中,“j * c[i]”是因为之前打出过j次伤害,如果这一位上是之间加伤害的话,那么到最后的时候,会多打出j次c[i]的额外伤害;“(k - i * j) * b[i]”表示的是这一位加上这个属性,之后,会有对应的j个位置打出伤害,每个位置对应的状态,利用状态差值得到,具体是这样的:

假设,分别在p1,p2,p3, …… ,px处打出伤害,那么,会有伤害的额外值增加:(p1 - i + p2 - i + p3 - i + …… + px - i) * b[i] = (p1 + p2 + p3 + ……  + px - x * i) * b[i];那么,我们得去遍历(p1 + p2 + p3 + …… + px)的状态,这个状态其实可以看作:如果我们从后面开始向前面取的话,那么就是从N、N-1、N-2、…… 、N-j+1,等于(N + N - j + 1)* j / 2;同样的道理,我们可以去求最小状态,就是i、i+1、i+2、……、i+j-1,等于(i + i + j - 1) * j / 2;我们遍历这其中的状态,然后都用状态k减去j * i即可。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 105;
ll N;
ll dp[2][maxN][maxN*50], tot;
struct node
{
    int A, B, C;
    node(int a=0, int b=0, int c=0):A(a), B(b), C(c) {}
}a[maxN];
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%lld", &N);
        for(int i=1; i<=N; i++) scanf("%d%d%d", &a[i].A, &a[i].B, &a[i].C);
        memset(dp, -1, sizeof(dp));
        dp[N&1][1][N] = a[N].A;
        tot = N * (N + 1)/2;
        for(ll i=N-1; i>=1; i--)   //第几次
        {
            int now = i&1, las = (i + 1)&1;  //滚动数组优化空间
            for(ll j=N-i; j>=1; j--)   //攻击总次数
            {
                ll down = (i + i + j - 1)*j/2, up = (N + N - j + 1)*j/2;
                for(ll k=up; k>=down; k--)
                {
                    dp[now][j+1][k+i] = max(dp[now][j+1][k+i], dp[las][j][k] + a[i].A); //打伤害的时候
                    dp[now][j][k] = max(dp[now][j][k], dp[las][j][k] + max(j * a[i].C, (k - i*j) * a[i].B));
                }
            }
            memset(dp[las], -1, sizeof(dp[las]));
        }
        ll ans = 0;
        for(int i=1; i<=N; i++)
        {
            for(int j=1; j<=tot; j++)
            {
                ans = max(ans, dp[1][i][j]);
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

给18年的一个交代吧,把这个DP给推出来了,还是进步了的,也去赛场吸取了教训,之后就要做的更好吧,19年!加油啦~

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/86373994