bzoj 2964 boss單挑戰 個人心得

明天還要期末考試今天還在浪。。。
題目鏈接:bzoj 2964
說來慚愧這題的思路是從網上找的題解看的,本來覺着很好寫,真正寫起來才發現有不少需要注意的地方;
主體思路是將法攻和怒功分開dp,本來以爲關於恢復生命的技能的使用次數做個加減法就好了,事實上並沒有這麼簡單,只好再進行一次dp;
由於本人太弱,實在想不起如何從i-1向i轉移,只能從i向i+1進行向後轉移,好像這樣也易於理解?
其中一定要牢記技能攻擊的順序,是先加血再受傷!!!
代碼:

#include<cstdio>
#include<algorithm>
const int maxn=1005;
using std::max;
using std::min;
int t,n,m,hp,mp,sp,dhp,dmp,dsp,x;
int DP[maxn][maxn];
struct asd
{
    int xh,ct;
};
asd b[11];
asd c[11];
void dtgh(int N,int sh,int hf,int maxp,asd *a,int num,int *ans)
{
    for(int i=0;i<=N;i++)
    {
        ans[i]=0;
        for(int j=0;j<=maxp;j++)
            DP[i][j]=0;
    }
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<=maxp;j++)
        {
            for(int k=0;k<=num;k++)
                if(k==0)
                {
                    int tmp=j+hf;
                    if(tmp>maxp)tmp=maxp;
                    DP[i+1][tmp]=max(DP[i][j]+sh,DP[i+1][tmp]);
                }
                else if(j>=a[k].xh)
                    DP[i+1][j-a[k].xh]=max(DP[i+1][j-a[k].xh],DP[i][j]+a[k].ct);
            ans[i]=max(ans[i],DP[i][j]);
        }
    }
    for(int i=0;i<=maxp;i++)ans[N]=max(ans[N],DP[N][i]);
}
int ai[maxn];
int ans1[maxn],ans2[maxn];
int bld[maxn][maxn];
int tim[maxn];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d%d%d%d%d%d",&n,&m,&hp,&mp,&sp,&dhp,&dmp,&dsp,&x);
        for(int i=1;i<=n;i++)scanf("%d",&ai[i]);
        int tmp;
        scanf("%d",&tmp);
        for(int i=1;i<=tmp;i++)scanf("%d%d",&b[i].xh,&b[i].ct);
        dtgh(n,0,dmp,mp,b,tmp,ans1);
        scanf("%d",&tmp);
        for(int i=1;i<=tmp;i++)scanf("%d%d",&c[i].xh,&c[i].ct);     
        dtgh(n,x,dsp,sp,c,tmp,ans2);
        int flag=0;
        int rhp=hp;
        tim[0]=0;
        for(int i=0;i<=n;i++)tim[i]=n+1;
        for(int i=0;i<=n;i++)
        for(int j=0;j<=hp;j++)bld[i][j]=n+1;
        bld[0][hp]=0;
        for(int i=0;i<n;i++)
        {
            for(int j=1;j<=hp;j++)
            {
                int tmp=j-ai[i+1];
                if(tmp>0)
                bld[i+1][tmp]=min(bld[i+1][tmp],bld[i][j]);
                if(j!=hp)
                {
                    tmp=j+dhp;
                    if(tmp>hp)tmp=hp;
                    tmp-=ai[i+1];//注意如果生命值滿了需要先加生命再受傷,這地方坑了我好久;
                    if(tmp>0)
                    bld[i+1][tmp]=min(bld[i+1][tmp],bld[i][j]+1);
                }
                tim[i]=min(tim[i],bld[i][j]);
            }
        }
        for(int i=1;i<=hp;i++)tim[n]=min(tim[n],bld[n][i]);
        for(int i=1;i<=n;i++)
        {   
            int tmpsh=0;
            for(int k=0;k<=i-tim[i-1];k++)
                tmpsh=max(ans1[k]+ans2[i-tim[i-1]-k],tmpsh);
            if(m<=tmpsh)
            {
                printf("Yes %d\n",i);
                flag=1;
                break;
            }
            if(tim[i]>i)
            {
                printf("No\n");
                flag=1;
                break;
            }       
        }
        if(!flag)printf("Tie\n");   
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章