通向自由的钥匙

来源:互联网 发布:千牛淘宝商品怎么分类 编辑:程序博客网 时间:2024/04/29 22:48

通向自由的钥匙


Description

通向自由的钥匙被放 n 个房间里,这 n 个房间由 n1 条走廊连接。
但是每个房间里都有特别的保护魔法,在它的作用下,我无法通过这个房间,也无法取得其中的钥匙。
虽然我可以通过消耗能量来破坏房间里的魔法,但是我的能量是有限的。
那么,如果我最先站在 1 号房间(1 号房间的保护魔法依然是有效的,也就是,如果不耗费能量,我无法通过 1 号房间,也无法取得房间中的钥匙),如果我拥有的能量为 P,我最多能取得多少钥匙?


Input

第一行包含两个非负整数,第一个为 N,第二个为 P
接下来 n 行,按 1 n 的顺序描述了每个房间。第 i+1 行包含两个非负整数 costkeys,分别为第 i 件房取消魔法需要耗费的能量和房间内钥匙的数量。
接下来 n1 行,每行两个非负整数 x,y,表示 x 号房间和 y 号是连通的。


Output

一行一个整数,表示取得钥匙的最大值。


Sample Input

5 5
1 2
1 1
1 1
2 3
3 4
1 2
1 3
2 4
2 5


Sample Output

7


Data Size

对于 20% 的测试数据,有 n<=20
对于 30% 的测试数据,有 n<=30
对于所有测试数据,有 p,n<=100, cost<=Maxint, keys<=Maxint


Solution

典型的树形依赖背包问题。
将需要的魔法视作重量,总魔法量视作容量,而钥匙数视作价值。
因为是无向图,跑一遍dfs变为有向图(起点当然为 1 啦)。
需要注意的是,如果魔法量变为 0 了,还需要特判一下,因为有些房间不要魔法就可以进去!!!


Code

#include <iostream>#include <cstdio>#define LL long long#define k s[end][0]#define tpm (s[top][1]-i-1+c[s[top][1]]-c[i]-l)#define mpt (s[top][1]-s[top][0]-1+c[s[top][1]]-c[s[top][0]]-l)#define tpm2 (s[top-1][1]-i-1+c[s[top-1][1]]-c[i]-l)#define mpt2 (s[top-1][1]-s[top-1][0]-1+c[s[top-1][1]]-c[s[top-1][0]]-l)#define Max(x,y) ((x)>(y)?(x):(y))#define Min(x,y) ((x)<(y)?(x):(y))using namespace std;LL n,l,top=0,end=0;LL c[50010];LL s[50010][3];LL f[50010];bool judge(LL x){    LL now=s[top][0];    LL pre=s[top-1][0];    return (f[now]+(x-now-1+c[x]-c[now]-l)*(x-now-1+c[x]-c[now]-l)<=f[pre]+(x-pre-1+c[x]-c[pre]-l)*(x-pre-1+c[x]-c[pre]-l));}LL find(LL l,LL r){    LL ans=2147483647;    while(l<=r){        LL mid=(l+r)/2;        if(judge(mid)){            ans=Min(ans,mid);            if(r!=mid-1)r=mid-1;            else break;        }        else{            if(l!=mid+1)l=mid+1;            else break;        }    }    return ans;}int main(){    scanf("%lld%lld",&n,&l);    for(LL i=1;i<=n;i++){        LL x;        scanf("%lld",&x);        c[i]=c[i-1]+x;    }    f[0]=0;    end=1;    s[++top][0]=0;s[top][1]=1;s[top][2]=n;    for(LL i=1;i<=n;i++){        while(i>s[end][2])end++;        LL tmp=(i-k-1+c[i]-c[k]-l);        f[i]=f[k]+tmp*tmp;        if(s[top][1]>i&&f[i]+tpm*tpm<=f[s[top][0]]+mpt*mpt){            s[top][0]=i;            while(top>1&&f[i]+tpm2*tpm2<=f[s[top-1][0]]+mpt2*mpt2){                s[--top][0]=i;                s[top][2]=s[top+1][2];            }            if(top>1)s[top-1][2]=s[top][1]-1;        }        else{            s[++top][0]=i;            s[top][2]=n;        }        if(top>1){            s[top][1]=find(Max(i+1,s[top-1][1]+1),n);            s[top-1][2]=s[top][1]-1;        }    }    printf("%lld\n",f[n]);    return 0;}
0 0
原创粉丝点击