zoukankan      html  css  js  c++  java
  • 团队题~~~黑皇杖

    题目描述:

    在战场上,每个英雄每秒都要承受魔法伤害。数字化地表述,第i秒会有ci点伤害。黑皇杖可以使英雄免疫连续若干秒的魔法伤害。黑皇杖第一次使用的时效为m秒,每次使用之后时效会减少一秒直到0秒。每次使用结束后,黑皇杖需要k秒的冷却时间。

    请你求出一个装备黑皇杖的英雄在T秒内最少要受到多少魔法伤害。黑皇杖可以在第一秒之前的任意时间就开始使用。

    输入输出格式:

    输入格式:

    第一行三个数T,M,K

    接下来一行T个数,c1,c2...cT.

    输出格式:

    一个数,表示最少的魔法伤害。

     T,M,K<=50000,保证中间量和答案均不超过2^31。

    输入输出样例:

    输入样例#1: 
    5 2 1
    3 2 1 1 2
    输出样例#1: 
    2
    输入样例#2: 
    10 4 1
    1 2 3 4 100 100 100 1 5 5
    输出样例#2: 
    5


    题目分析:
    这是一道很恶心的动态规划题目...恶心的地方呢,首先是数据范围
    dp的状态设计,一般可以从数据范围看出来,可以硬凑复杂度,然而这个题
    看到数据范围就吓了一跳。五万???这是要让我什么复杂度??????
    仔细分析,虽然数据范围给了五万,但其实,有一个数字是几乎不可能达到给定的五万的
    -----黑皇仗的使用次数
    考虑最坏的情况下,cd为0综合考虑,每次使用使时间减少1和总时间的限制,使用次数k必然<=500
    能分析到这一步,就解决本题一个很大的难点了,500,5w,复杂度相乘显然正好,于是我们定义状态
    dp[i][j]表示前i单位的时间内,总共使用了j次黑皇杖,受到的最少伤害
    仍要解决的问题:细节!!!!!!!【我在这里卡了好久】
    这里的使用j次黑皇杖,其实说的很不严谨
    1 -> 这j次都已经使用完了(这j次的时间都到了)
    2 -> 使用了j次,最后一次不一定使用完
    分析这两种方案各自的利弊:
    方案1,这个状态设计让我们转移方程很显然,
    dp[i][j] = min(这一秒的伤害没有挡住,前i - 1秒时就用完了j次,这一秒刚好用完第j次)
    dp完成之后,问题来了。答案是谁??????我们注意到最优情况时,可能最后一次还在使用,所以无法统计答案
    方案2,完美解决了方案1的劣势,答案是dp[i][1 ~ k]取max
    但是,由于到一个时间时,不知道上一次使用的时间还剩多少,没发转移
    正解:方案1
    对于这一种方案,我们的问题是,无法统计答案。
    那么考虑,在这一状态下,答案会出现在哪里呢?
    我们的状态设计是:在这一时间刚好用完了这一次黑皇杖,最优解的情况可能最后一次法杖是时间答案t时时间仍有剩余
    那么答案出现的位置是:时间(t + res)的位置刚好结束
    于是,我们可以把dp数组的第一维开大一倍,考虑在第(t + m)时间内刚好结束最后一次使用的答案,就解决了统计答案问题了

    CODES:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 
     6 #define RI register int
     7 using namespace std;
     8 typedef long long ll;
     9 
    10 const int INF = 1e9 + 7;
    11 const int MAXN = 100000 + 5;
    12 
    13 #define max(a,b) ((a) > (b) ? (a) : (b))
    14 #define min(a,b) ((a) < (b) ? (a) : (b))
    15 
    16 inline void read(int &x)
    17 {
    18     x = 0;
    19     bool flag = 0;
    20     char ch = getchar();
    21     while(ch < '0' || ch > '9')
    22     {
    23         if(ch == '-')    flag = 1;
    24         ch = getchar();
    25     }
    26     while(ch >= '0' && ch <= '9')
    27     {
    28         x = (x << 3) + (x << 1) + ch - '0';
    29         ch = getchar();
    30     }
    31     if(flag)    x *= -1;
    32 }
    33 
    34 int t,m,cd,k,tmp,now,ans = INF;
    35 int dp[MAXN][505],num[MAXN],sum[MAXN];
    36 
    37 int main()
    38 {
    39     read(t),read(m),read(cd);
    40     for(RI i = 1;i <= t;i ++)
    41         read(num[i]);
    42     for(RI i = 1;i <= (t + m);i ++)
    43         sum[i] = sum[i - 1] + num[i];
    44     tmp = m,now = k = 0;
    45     while(tmp && now <= t)
    46     {now += tmp;now += cd;tmp --;k ++;}
    47     for(RI i = 1;i <= (t + m);i ++)
    48     {
    49         for(RI j = 0;j <= k;j ++)
    50         {
    51             if(!j)    dp[i][j] = sum[i];
    52             else
    53             {
    54                 dp[i][j] = dp[i - 1][j] + num[i];
    55                 dp[i][j] = min(dp[i][j],
    56                 dp[max(0,i - (m - j + 1) - cd)][j - 1] + 
    57                 sum[max(0,i - m + j - 1)] - sum[max(0,i - m + j - 1 - cd)]);
    58             }
    59             if(i >= t)    ans = min(ans,dp[i][j]);
    60         }
    61     }
    62     printf("%d
    ",ans);
    63     return 0;
    64 }
    View Code


  • 相关阅读:
    day 49
    day 48
    day 46
    IOC和DI到底是什么?
    堆排序算法
    快速排序算法
    java中try-catch-finally中的return语句
    归并排序算法
    选择排序算法
    冒泡排序算法
  • 原文地址:https://www.cnblogs.com/illyaillyasviel/p/7718990.html
Copyright © 2011-2022 走看看