3875: [Ahoi2014]骑士游戏
Time Limit: 30 Sec
Memory Limit: 256 MB
Submit: 599
Solved: 319
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
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的做法,令fi:杀死第i中怪物的最小消耗
那么fi = min(∑fk + si,ki) ∑fk就是把所有分裂出来的怪物都杀死的最小代价
貌似一个记搜就能搞定??
但是很明显,这个dp会出现死循环的情况,,
原因是用普通攻击杀死怪物的时候,再次普通攻击,循环下去可能会出现之前杀过的怪物
说明说这个杀死怪物出现的环一定要在某处断开
考虑某个时刻,有些怪物,手动杀死他后出现的所有新怪物的fj都被算出来了,
那么当前这个fi也就出来了,当fi出来后,我们就能像DAG上dp那样把这只怪物扔进队列去弄
但是DAG上的dp是基于拓扑序的
如果某一时刻,剩余所有怪物的出度都不为0,这个dp就无法下去
但是这种情况下,对于那只用魔法杀死代价最小的怪物,它的fi也被确定了
就是直接用魔法杀死他的代价
因为此时如果再用普通攻击,新衍生的怪物总得被魔法杀死,但是这只怪物已经是消耗最小的了,不可能再少
因此,不断选出当前魔法攻击消耗最小的怪物,不断跑BFS,这题就解决了
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 2E5 + 20;
typedef long long LL;
const LL INF = 1E17;
struct data{
int num; LL c; data(){}
data(int num,LL c): num(num),c(c){}
bool operator < (const data &b) const {return c > b.c;}
};
struct E{
int to,w; E(){}
E(int to,int w): to(to),w(w){}
};
int n,m,cnt,pass,du[maxn],vis[maxn],g[maxn],a[maxn*10];
LL f[maxn],tot[maxn],S[maxn];
bool bo[maxn];
vector <E> v[maxn];
priority_queue <data> Q;
queue <int> q;
void Add()
{
if (pass == n) return;
for (;;) {
data k = Q.top(); Q.pop();
if (bo[k.num]) continue;
bo[k.num] = 1; ++pass;
q.push(k.num); return;
}
}
void BFS()
{
while (!q.empty()) {
int k = q.front(); q.pop();
for (int i = 0; i < v[k].size(); i++) {
E e = v[k][i]; --du[e.to];
if (bo[e.to]) continue;
tot[e.to] += 1LL*e.w*f[k];
tot[e.to] = min(tot[e.to],INF);
if (!du[e.to]) {
f[e.to] = min(f[e.to],tot[e.to] + S[e.to]);
++pass; bo[e.to] = 1; q.push(e.to);
}
}
}
}
LL getLL()
{
char ch = getchar();
LL ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret*10LL + 1LL*(ch - '0'),ch = getchar();
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getLL();
for (int i = 1; i <= n; i++) {
S[i] = getLL(); f[i] = getLL();
Q.push(data(i,f[i]));
m = getLL(); ++cnt;
for (int j = 1; j <= m; j++) {
a[j] = getLL();
if (vis[a[j]] != cnt) g[a[j]] = 0;
++g[a[j]]; vis[a[j]] = cnt;
}
++cnt;
for (int j = 1; j <= m; j++)
if (vis[a[j]] != cnt) {
v[a[j]].push_back(E(i,g[a[j]]));
vis[a[j]] = cnt; ++du[i];
}
}
for (int i = 1; i <= n; i++)
if (!du[i]) ++pass,q.push(i),bo[i] = 1;
for (; pass < n; Add()) BFS();
cout << f[1];
return 0;
}