[bzoj3875][Ahoi2014]骑士游戏
Description
【故事背景】
长期的宅男生活中,JYY又挖掘出了一款RPG游戏。在这个游戏中JYY会
扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽。
【问题描述】
在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻
击。两种攻击方式都会消耗JYY一些体力。采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽;而采用法术攻击则可以彻底将一个怪兽杀死。当然了,一般来说,相比普通攻击,法术攻击会消耗更多的体力值(但由于游戏系统bug,并不保证这一点)。
游戏世界中一共有N种不同的怪兽,分别由1到N编号,现在1号怪兽入
侵村庄了,JYY想知道,最少花费多少体力值才能将所有村庄中的怪兽全部杀死呢?
Input
第一行包含一个整数N。
接下来N行,每行描述一个怪兽的信息;
其中第i行包含若干个整数,前三个整数为Si,Ki和Ri,表示对于i号怪兽,
普通攻击需要消耗Si的体力,法术攻击需要消耗Ki的体力,同时i号怪兽死亡后会产生Ri个新的怪兽。表示一个新出现的怪兽编号。同一编号的怪兽可以出现多个。
Output
输出一行一个整数,表示最少需要的体力值。
Sample Input
4
4 27 3 2 3 2
3 5 1 2
1 13 2 4 2
5 6 1 2
4 27 3 2 3 2
3 5 1 2
1 13 2 4 2
5 6 1 2
Sample Output
26
HINT
【样例说明】
首先用消耗4点体力用普通攻击,然后出现的怪兽编号是2,2和3。花费
10点体力用法术攻击杀死两个编号为2的怪兽。剩下3号怪兽花费1点体力进
行普通攻击。此时村庄里的怪兽编号是2和4。最后花费11点体力用法术攻击
将这两只怪兽彻底杀死。一共花费的体力是4+5+5+1+5+6=26。
【数据范围】
2<=N<=2*10^5,1<=Ri,Sigma(Ri)<=10^6,1<=Ki,Si<=5*10^14
Source
dp转移方程显而易见,设f[i]为杀死i所需最小代价,则f[i]=min(K[i],s[i]+∑f[t]) (t为i所有儿子),但dp偏序灰常不明确
可以利用Super_Fast的玄学思想,一开始将每个点都放入队列(相当于强制转移),当一个点被更新时,将其所有父亲放入队列,更新它的父亲。
还有一定不会重复更新环,因为有环的话f值只会越来越大
1 // It is made by XZZ 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 #define rep(a,b,c) for(rg int a=b;a<=c;a++) 6 #define drep(a,b,c) for(rg int a=b;a>=c;a--) 7 #define erep(a,b) for(rg int a=fir[b];a;a=nxt[a]) 8 #define il inline 9 #define rg register 10 #define vd void 11 #define t (dis[i]) 12 typedef long long ll; 13 il ll gi(){ 14 rg ll x=0;rg char ch=getchar(); 15 while(ch<'0'||ch>'9')ch=getchar(); 16 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 17 return x; 18 } 19 const int maxn=200010,maxm=1000001<<1; 20 int fir[maxn],dis[maxm],nxt[maxm],id=1; 21 il vd add(int a,int b,int first=1){ 22 nxt[++id]=fir[a],fir[a]=id,dis[id]=b; 23 if(first)add(b,a,0); 24 } 25 ll s[maxn],k[maxn],f[maxn]; 26 ll que[maxn],hd,tl; 27 bool inque[maxn]; 28 int main(){ 29 ll n=gi(),r; 30 rep(i,1,n){ 31 s[i]=gi(),k[i]=f[i]=gi(),r=gi(); 32 while(r--)add(i,gi()); 33 } 34 hd=0,tl=n; 35 rep(i,1,n)que[i-1]=i,inque[i]=1; 36 while(hd^tl){ 37 int now=que[hd]; 38 ll res=s[now]; 39 erep(i,now)if(i%2==0)res+=f[t]; 40 if(res<f[now]){ 41 f[now]=res; 42 erep(i,now)if(i%2&&!inque[t]) 43 que[tl++]=t,inque[t]=1,tl%=maxn; 44 } 45 ++hd,hd%=maxn,inque[now]=0; 46 } 47 printf("%lld\n",f[1]); 48 return 0; 49 }
博主是蒟蒻,有问题请指出,谢谢!
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。