prow2012-A3-0020

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
题意:打普通怪不耗血瓶可以积累一个buf,有了5个buf就可以打boss,打死boss要消耗血瓶,
可以积累一个胜利点。问取得最多胜利点的同时耗血瓶最少是多少。

主要就是耗血瓶的数量怎么求,一开始用二分血瓶数量+验证是否够,验证的方法太土,超时了,
改成f[1000][1000][10]的DP,还是太土,跑得快超时了。

猛马的求血瓶方法是特判算出来的,大家快去仰慕他的解题报告。。。
}}}





{{{

#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <map>
#include <sstream>
#include <string>
#include <math.h>
using namespace std;
#define maxn 50100
int N,HP,D,P,h[maxn],d[maxn],f[maxn][6][2];
int use[maxn],rd,type[maxn];
int g[1010][1010][11];
int oo = 1000000000;

void update(int i,int j,int a,int b){
    if (a>f[i][j][0]){
        f[i][j][0] = a;
        f[i][j][1] = b;
    }else if (a==f[i][j][0]&&b<f[i][j][1]){
        f[i][j][0] = a;
        f[i][j][1] = b;
    }
}

int getg(int hp,int h,int d){
    if (hp<=0) return oo;
    if (h-D<=0) return 0;

    if (g[hp][h][d]!=-1) return g[hp][h][d];
    int Min = getg(min(HP,hp+P)-d,h-D,d) +1;
    if (hp-d>0)
    {
        Min = min(Min,getg(min(HP,hp-d+P),h-D,d)+1);
        Min = min(Min,getg(hp-d,h-D,d));
    }
    g[hp][h][d] = Min;
//  printf("%d %d %d: %d\n",hp,h,d,Min);
    return Min;
}

int main(){
    int i,j,k;
    while(scanf("%d",&N)!=EOF){
        for (i=1;i<=N;i++)
        {
            scanf("%d",type+i);
            if (type[i]==1){
                scanf("%d%d",h+i,d+i);
            }
        }
        scanf("%d%d%d",&HP,&D,&P);

        for (k = 1;k<=10;k++)
            for (j = 1000;j>0;j--)
                for (i=1;i<=HP;i++)
                    g[i][j][k] = -1;




        for (i=1;i<=N+2;i++){
            if (i<=N&&type[i]==1){
                use[i] = getg(HP,h[i],d[i]);
            }else use[i] = oo;
        //  printf("%d %d---\n",i,use[i]);
            for (j=0;j<=5;j++)
                f[i][j][0] = -1,f[i][j][1] = oo;
        }




        f[1][0][0] = f[1][0][1]  = 0;
        for (i=1;i<=N;i++)
            for (j=0;j<=5;j++)
            if (f[i][j][0]!=-1){
            if (type[i]==0) {
                update(i+1,min(j+1,5),f[i][j][0],f[i][j][1]);
            }else {
                update(i+1,j,f[i][j][0],f[i][j][1]);
                if (j==5&&use[i]<oo){
                    update(i+1,0,f[i][j][0]+1,f[i][j][1]+use[i]);
                }
            }
            }

        for (j=0;j<=5;j++)
            update(N+2,0,f[N+1][j][0],f[N+1][j][1]);
        printf("%d %d\n",f[N+2][0][0],f[N+2][0][1]);
    }
}


}}}
题意:打普通怪不耗血瓶可以积累一个buf,有了5个buf就可以打boss,打死boss要消耗血瓶,
可以积累一个胜利点。问取得最多胜利点的同时耗血瓶最少是多少。
主要就是耗血瓶的数量怎么求,一开始用二分血瓶数量+验证是否够,验证的方法太土,超时了,
改成f[1000][1000][10]的DP,还是太土,跑得快超时了。
猛马的求血瓶方法是特判算出来的,大家快去仰慕他的解题报告。。。
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <set>
#include <map>
#include <sstream>
#include <string>
#include <math.h>
using namespace std;
#define maxn 50100
int N,HP,D,P,h[maxn],d[maxn],f[maxn][6][2];
int use[maxn],rd,type[maxn];
int g[1010][1010][11];
int oo = 1000000000;
void update(int i,int j,int a,int b){
    if (a>f[i][j][0]){
        f[i][j][0] = a;
        f[i][j][1] = b;
    }else if (a==f[i][j][0]&&b<f[i][j][1]){
        f[i][j][0] = a;
        f[i][j][1] = b;
    }
}
int getg(int hp,int h,int d){
    if (hp<=0) return oo;
    if (h-D<=0) return 0;
    if (g[hp][h][d]!=-1) return g[hp][h][d];
    int Min = getg(min(HP,hp+P)-d,h-D,d) +1;
    if (hp-d>0)
    {
        Min = min(Min,getg(min(HP,hp-d+P),h-D,d)+1);
        Min = min(Min,getg(hp-d,h-D,d));
    }
    g[hp][h][d] = Min;
//  printf("%d %d %d: %d\n",hp,h,d,Min);
    return Min;
}
int main(){
    int i,j,k;
    while(scanf("%d",&N)!=EOF){
        for (i=1;i<=N;i++)
        {
            scanf("%d",type+i);
            if (type[i]==1){
                scanf("%d%d",h+i,d+i);
            }
        }
        scanf("%d%d%d",&HP,&D,&P);
        for (k = 1;k<=10;k++)
            for (j = 1000;j>0;j--)
                for (i=1;i<=HP;i++)
                    g[i][j][k] = -1;
        for (i=1;i<=N+2;i++){
            if (i<=N&&type[i]==1){
                use[i] = getg(HP,h[i],d[i]);
            }else use[i] = oo;
        //  printf("%d %d---\n",i,use[i]);
            for (j=0;j<=5;j++)
                f[i][j][0] = -1,f[i][j][1] = oo;
        }
        f[1][0][0] = f[1][0][1]  = 0;
        for (i=1;i<=N;i++)
            for (j=0;j<=5;j++)
            if (f[i][j][0]!=-1){
            if (type[i]==0) {
                update(i+1,min(j+1,5),f[i][j][0],f[i][j][1]);
            }else {
                update(i+1,j,f[i][j][0],f[i][j][1]);
                if (j==5&&use[i]<oo){
                    update(i+1,0,f[i][j][0]+1,f[i][j][1]+use[i]);
                }
            }
            }
        for (j=0;j<=5;j++)
            update(N+2,0,f[N+1][j][0],f[N+1][j][1]);
        printf("%d %d\n",f[N+2][0][0],f[N+2][0][1]);
    }
}