zoukankan      html  css  js  c++  java
  • 【BZOJ 2964】Boss单挑战

    Description

      某RPG游戏中,最后一战是主角单挑Boss,将其简化后如下:
      主角的气血值上限为HP,魔法值上限为MP,愤怒值上限为SP;Boss仅有气血值,其上限为M。
      现在共有N回合,每回合都是主角先行动,主角可做如下选择之一:
      1. 普通攻击:减少对方X的气血值,并增加自身DSP的愤怒值。(不超过上限)
      2. 法术攻击:共有N1种法术,第i种消耗Bi的魔法值,减少对方Yi的气血值。(使用时要保证MP不小于Bi)
      3. 特技攻击:共有N2种特技,第i种消耗Ci的愤怒值,减少对方Zi的气血值。(使用时要保证SP不小于Ci)
      4. 使用HP药水:增加自身DHP的气血值。(不超过上限)
      5. 使用MP药水:增加自身DMP的魔法值。(不超过上限)
      之后Boss会攻击主角,在第i回合减少主角Ai的气血值。
      刚开始时气血值,魔法值,愤怒值都是满的。当气血值小于等于0时死亡。
      如果主角能在这N个回合内杀死Boss,那么先输出“Yes”,之后在同一行输出最早能在第几回合杀死Boss。(用一个空格隔开)
      如果主角一定会被Boss杀死,那么输出“No”。
      其它情况,输出“Tie”。

    Input

      输入的第一行包含一个整数T,为测试数据组数。
      接下来T部分,每部分按如下规则输入:
      第一行九个整数N, M, HP, MP, SP, DHP, DMP, DSP, X。
      第二行N个整数Ai。
      第三行第一个整数N1,接下来包含N1对整数Bi, Yi。
      第四行第一个整数N2,接下来包含N2对整数Ci, Zi。

    Output

      输出共包含T行,每行依次对应输出一个答案。

    Sample Input

    2
    5 100 100 100 100 50 50 50 20
    50 50 30 30 30
    1 100 40
    1 100 40
    5 100 100 100 100 50 50 50 10
    50 50 30 30 30
    1 100 40
    1 100 40

    Sample Output

    Yes 4
    Tie
    样例说明
      对于第一个样例,主角的策略是:第一回合法术攻击,第二回合使用HP药水,第三回合特技攻击,第四回合普通攻击。

    HINT

      对于100%的数据:1 ≤ N ≤ 1000,1 ≤ M ≤ 1000000,1 ≤ HP,MP,SP ≤ 1000,N1,N2 ≤ 10,DHP,Ai ≤ HP,DMP,Bi ≤ MP,DSP,Ci ≤ SP,X,Yi,Zi ≤ 10000,1 ≤ T ≤ 10。

    分析:

      考虑到HP、MP、SP之间是相互独立的,且MP、SP是回合无关的(只与回合总数有关,与在哪一回合攻击无关),所以可以先分别对MP和SP进行DP,F[i][j]表示进行i次MP/SP的操作后,剩下MP/SP为j,对Boss造成的最大伤害,再记录G1[i]和G2[i]分别表示进行i次MP/SP的操作,对Boss造成的最大伤害。

      枚举i、j,统计当G1[i]+G2[j]>=M时,i+j的最小值mincost,这就是打倒Boss的最少操作次数(与HP无关)。

      最后再考虑HP,HP是和回合有关的,所以DP的时候要考虑回合。用F[i][j]表示在第i回合之前,还剩下的HP为j,最多有多少次MP/SP的操作次数,包括当前第i回合。

      若存在F[i][j]>=mincost(i<=n、j>0),那么输出Yes,最小的i即为答案。

      否则,判断No或Tie,在DP之前将F[i][j]初始化为极小的负数,若存在F[N + 1][j]>=0(j>0),则表示N回合之内主角可以不死,却也打不死Boss,即输出Tie,否则输出No。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3  
     4 int n, m, hp, mp, sp, dhp, dmp, dsp, x;
     5 int a[1010], kmp[1010][2], ksp[1010][2], km, ks;
     6 int dp_mp[1010][1010], dp_sp[1010][1010], fm[1010], fs[1010];
     7 int f[1010][1010];
     8  
     9 int min(int A, int B) { return A < B ? A : B;}
    10 void checkmin(int &A, int B) { A > B ? A = B : 0;}
    11 void checkmax(int &A, int B) { A < B ? A = B : 0;}
    12  
    13 int solve()
    14 {
    15     memset(dp_mp, 0, sizeof dp_mp);
    16     memset(dp_sp, 0, sizeof dp_sp);
    17     memset(fm, 0, sizeof fm);
    18     memset(fs, 0, sizeof fs);
    19     memset(f, 180, sizeof f);
    20     scanf("%d%d%d%d%d", &n, &m, &hp, &mp, &sp);
    21     scanf("%d%d%d%d", &dhp, &dmp, &dsp, &x);
    22     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    23     scanf("%d", &km);
    24     for (int i = 1; i <= km; i++)
    25         scanf("%d%d", &kmp[i][0], &kmp[i][1]);
    26     scanf("%d", &ks);
    27     for (int i = 1; i <= ks; i++)
    28         scanf("%d%d", &ksp[i][0], &ksp[i][1]);
    29     for (int i = 0; i <= n; i++)
    30     {
    31         for (int j = 0; j <= mp; j++)
    32         {
    33             checkmax(fm[i], dp_mp[i][j]);
    34             for (int k = 1; k <= km; k++) if (j >= kmp[k][0])
    35                 checkmax(dp_mp[i + 1][j - kmp[k][0]], dp_mp[i][j] + kmp[k][1]);
    36             checkmax(dp_mp[i + 1][min(j + dmp, mp)], dp_mp[i][j]);
    37         }
    38     }
    39     for (int i = 0; i <= n; i++)
    40     {
    41         for (int j = 0; j <= sp; j++)
    42         {
    43             checkmax(fs[i], dp_sp[i][j]);
    44             for (int k = 1; k <= ks; k++) if (j >= ksp[k][0])
    45                 checkmax(dp_sp[i + 1][j - ksp[k][0]], dp_sp[i][j] + ksp[k][1]);
    46             checkmax(dp_sp[i + 1][min(j + dsp, sp)], dp_sp[i][j] + x);
    47         }
    48     }
    49     int mincost = 99999999;
    50     for (int i = 0; i <= n; i++)
    51         for (int j = 0; j <= n; j++)
    52             if (fm[i] + fs[j] >= m)
    53                 checkmin(mincost, i + j);
    54     f[1][hp] = 1;
    55     for (int i = 1; i <= n; i++)
    56     {
    57         for (int j = 1; j <= hp; j++)
    58         {
    59             if (f[i][j] >= mincost)
    60                 return printf("Yes %d
    ", i);
    61             if (j > a[i]) checkmax(f[i + 1][j - a[i]], f[i][j] + 1);
    62             if (min(j + dhp, hp) > a[i])
    63                 checkmax(f[i + 1][min(j + dhp, hp) - a[i]], f[i][j]);
    64         }
    65     }
    66     for (int j = 1; j <= hp; j++)
    67         if (f[n + 1][j] >= 0)
    68             return printf("Tie
    ");
    69     printf("No
    ");
    70 }
    71  
    72 int main()
    73 {
    74     int t;
    75     scanf("%d", &t);
    76     while (t--) solve();
    77 }
  • 相关阅读:
    使用批处理bat作为日期系统日期的前三天
    电脑桌面显示倒退
    BZOJ 2648/2716(SJY把件-KD_Tree)[Template:KD_Tree]
    yii使用寻呼功能
    宝付额度
    vs2010旗舰版产品密钥
    考察网贷平台是否正规,仅供参考。
    sql server 修改字段大小
    帕累托分析法
    帕累托分析法(Pareto Analysis)(柏拉图分析)
  • 原文地址:https://www.cnblogs.com/lightning34/p/4802526.html
Copyright © 2011-2022 走看看