[csu oj 2071 Spellcasting]贪心+微分方程
分类:Greedy
math
1. 题目链接
2. 题意描述
【题意比较繁琐??】
一开始你有
E
E
点能量,能量可以用来造任意数量的元素(实数),并且立刻造完,造完之后加力量,力量的意思是每秒可以产生的能量数目。
现在有种元素,每种元素每单位需用
ei
e
i
点能量造,可加
pi
p
i
点力量,它的父亲是
fi
f
i
。
N
N
种元素构成树或者森林,每单位的父亲可以使每单位的儿子花费减半。
问最后要达到点力量需要多少秒钟。
每个节点儿子可能不止一个,所以假如A的儿子是B和C , 那么如果先造1单位A, 那么可以让0.8单位B和0.2单位C的花费各自减半。只要B,C加起来小于1就可以减半。大于1的部分就是原价了。
数据范围:
1≤N≤1000,1≤E≤109,1≤P≤109
1
≤
N
≤
1000
,
1
≤
E
≤
10
9
,
1
≤
P
≤
10
9
1≤ei≤109,0≤pi≤109
1
≤
e
i
≤
10
9
,
0
≤
p
i
≤
10
9
3. 解题思路
首先,对于输入的树(森林),我们需要找到一条性价比最高的一条链,初始情况下,把全部的能量全部都分给这条链上,且每个元素分配同样多的能量。然后,就可以发现,其实就可以把这条链看成一个元素了。因为树(森林)的节点最多
N
N
个,可以考虑
O(n2)
O
(
n
2
)
暴力枚举每条链。
看成一个元素之后,那就是一个很简单的微分方程的求解了呀!
设这个元素,每单位召唤需要
e¯¯¯
e
¯
点能量,然后每单位该元素每秒可以产生
p¯¯¯
p
¯
点能量吧。
设时间为
t
t
时,总的能量为吧,那么
B(0)=E
B
(
0
)
=
E
。
那么有,
然后可以有:
两边同时积分:
即:
由 B(0)=E B ( 0 ) = E 得: 常数=−E 常 数 = − E
那么,有
那么,对 B(t) B ( t ) 求导,就是答案了呀!
最后,还要记得下面两种特判:
- 一种情况是:这条链初始power就大于等于 P P 了,答案自然为;
- 还有就是:这条链 p¯¯¯=0 p ¯ = 0 ,也就是说,总的能量不会涨,power永远也到不了 P P <script type="math/tex" id="MathJax-Element-60">P</script>,那么时间就是无限长。
4. 实现代码
#include <ctime>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll infl = 0x3f3f3f3f3f3f3f3fLL;
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
void debug() { cout << endl; }
template<typename T, typename ...R>
void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }
const int MAXN = 1005;
int fa[MAXN];
struct Node {
ll e, p;
} node[MAXN];
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
ll N, E, P;
while(cin >> N >> E >> P) {
if(!N && !E && !P) break;
for(int i = 1; i <= N; ++i) {
cin >> node[i].e >> node[i].p >> fa[i];
}
ll ans = infl;
for(int u = 1; u <= N; ++u) {
long double sum_e = 0;
long double sum_p = 0;
for(int v = u, cnt = 1; v != 0; v = fa[v], ++cnt) {
sum_e += node[v].e * 0.5;
sum_p += node[v].p;
long double e = (sum_e + node[v].e * 0.5) / cnt;
long double p = sum_p / cnt;
if(fabs(p) <= 1e-8) continue; // 时间无限长
if(P * e <= p * E) { // 初始情况下,就达到要求了
ans = 0;
break;
}
umin(ans, (ll)ceil(e / p * log(e / p * P / E)));
}
}
cout << ans << endl;
}
#ifdef ___LOCAL_WONZY___
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
return 0;
}