【YBTOJ】【CodeForces 372C】Watching Fireworks is Fun

时间:2021-08-08
本文章向大家介绍【YBTOJ】【CodeForces 372C】Watching Fireworks is Fun,主要包括【YBTOJ】【CodeForces 372C】Watching Fireworks is Fun使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Watching Fireworks is Fun

链接:

洛谷

博客园

题目大意:

一个城镇有 \(n\) 个区域,从左到右 \(1\) 编号为 \(n\),每个区域之间距离 \(1\) 个单位距离。节日中有 \(m\) 个烟火要放,给定放的地点 \(a_i\),时间 \(t_i\),如果你当时在区域 \(x\),那么你可以获得 \(b_i - \vert a_i - x\vert\) 的开心值。你每个单位时间可以移动不超过 \(d\) 个单位距离。你的初始位置是任意的(初始时刻为 \(1\)),求你通过移动能获取到的最大的开心值。

正文:

考虑 DP,设 \(f_{i,j}\) 表示当前放第 \(i\) 个烟花且在位置 \(j\) 时的最大开心值。则有:

\[f_{i,j}=\max_{k,|j-k|\leq(t_i-t_{i-1})d}\left\{f_{i-1,k}+b_i-|a_i-j|\right\} \]

考虑到可以将 \(b_i\) 提出,得到:

\[f_{i,j}=\max_{k,|j-k|\leq(t_i-t_{i-1})d}\left\{f_{i-1,k}-|a_i-j|\right\} \]

我们可以用单调队列优化上面的式子。

最后答案为:

\[\sum_{i=1}^m b_i + \max_{i=1}^n\{f_{m,i}\} \]

但是空间复杂度 \(\mathcal{O}(nm)\),用滚动数组优化至 \(\mathcal{O}(n)\) 即可。

代码:

const int N = 150010, M = 310;

inline ll Read()
{
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, m, d; 
ll f[2][N];
struct node
{
	int a, t;
}a[M];
deque <int> q;
ll sum, ans = -(1ll << 60);

int main()
{
	n = Read(), m = Read(), d = Read();
	for (int i = 1; i <= m; i++)
		a[i].a = Read(), sum += Read(), a[i].t = Read();
	for (int i = 1; i <= m; i++)
	{
		ll len = (ll)(a[i].t - a[i - 1].t) * d;
		for (; !q.empty(); q.pop_back());
		for (int j = 1; j <= n; j++)
		{
			for (; !q.empty() && q.front() < j - len; q.pop_front());
			for (; !q.empty() && f[i & 1 ^ 1][j] > f[i & 1 ^ 1][q.back()]; q.pop_back());
			q.push_back(j);
			f[i & 1][j] = f[i & 1 ^ 1][q.front()] - abs(a[i].a - j);
		}
		
		for (; !q.empty(); q.pop_back());
		for (int j = n; j >= 1; j--)
		{
			for (; !q.empty() && q.front() > j + len; q.pop_front());
			for (; !q.empty() && f[i & 1 ^ 1][j] > f[i & 1 ^ 1][q.back()]; q.pop_back());
			q.push_back(j);
			f[i & 1][j] = max(f[i & 1][j], f[i & 1 ^ 1][q.front()] - abs(a[i].a - j));
		}
	}
	
	for (int i = 1; i <= n; i++)
		ans = max(ans, f[m & 1][i]);
	ans = sum + ans;
	printf ("%lld", ans);
	return 0;
}

原文地址:https://www.cnblogs.com/GJY-JURUO/p/15114916.html