CF1396C Monster Invaders

CF1396C Monster Invaders

自己做出来的蓝题 dp,喜。

容易得到如下结论:

1、每关内部比较独立。

2、小关没杀完就走一定不优。

3、经过计算可得,杀一个关卡只有三种方式:(前者为杀小怪的方式,后者为杀 boss 的方式,计算式里面同理)

​ 方式一:手枪 + AWP \(a_i \times r_1 + r_3\)

​ 方式二:手枪 + 手枪 \(a_i \times r_1 + 2 \times r_1\),另外还有 \(2 \times d\) 的移动代价。

​ 方式三:激光枪 + 手枪 \(r_2 + r_1\),另外还有 \(2 \times d\) 的移动代价。

4、我们记结论 \(3\) 中采用方式二、三的关卡为回头点,可以证明在 \(i + 1\) 处返回回头点 \(i\),这样全部通关所产生的额外移动代价最小。

根据结论 \(1\),很容易想到本题可以使用 dp。

根据结论 \(3,4\),发现该转移存在两种特殊情况:

1、对于连续多个回头点,可以两两匹配减少移动代价。因此转移要分奇偶。

2、当第 \(n - 1\) 关是一个单独的回头点,且第 \(n\) 关不是回头点时,移动代价只有 \(d\)

我们记 \(f_{i, j, k}\) 表示前 \(i\) 关,第 \(i\) 关不是 / 是(\(j = 0 / 1\))回头点,若是,第 \(i\) 关是连续的第偶数 / 奇数(\(k = 0/1\))个回头点。转移方程显然。

时间复杂度 \(O(n)\)

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int N = 1500000;
const ll inf = 1e18;
ull n, r1, r2, r3, d;
int a[N];
ull f[N][2][2], ans = inf;
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n >> r1 >> r2 >> r3 >> d;
	F(i, 1, n) cin >> a[i];
	f[1][0][0] = a[1] * r1 + r3;
	f[1][1][1] = min((a[1] + 2) * r1, r2 + r1) + 2 * d;
	f[1][1][0] = inf;
	
	F(i, 2, n){
		f[i][0][0] = min({f[i - 1][0][0], f[i - 1][1][1], f[i - 1][1][0]}) + a[i] * r1 + r3;
		f[i][1][1] = min(f[i - 1][1][0], f[i - 1][0][0]) + min(r2 + r1, (a[i] + 2) * r1) + 2 * d;
		f[i][1][0] = f[i - 1][1][1]+ min(r2 + r1, (a[i] + 2) * r1);
	}
	f[n][0][0] = min(f[n - 1][1][1] + a[n] * r1 + r3 - d, f[n][0][0]);
//	F(i, 1, n){
//		printf("%llu\t%llu\t%llu\t%llu\t%llu\n", f[i][0][0], f[i][1][0], f[i][1][1], f[i][2][0], f[i][2][1]);
//	}
	cout << min({f[n][0][0], f[n][1][0], f[n][1][1]}) + (n - 1) * d << '\n';
	return fflush(0), 0;
}
posted @ 2025-08-06 16:10  superl61  阅读(7)  评论(0)    收藏  举报