zoukankan      html  css  js  c++  java
  • 【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 - xvert) 的开心值。你每个单位时间可以移动不超过 (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| ight} ]

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

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

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

    最后答案为:

    [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;
    }
    
  • 相关阅读:
    为什么做java开发的公司需要那么多程序员?
    一篇文章了解架构设计的本质
    深入理解 Java 多线程核心知识
    面试经验总结:注意这几点,面试通过率上涨30%
    程序员一般做到多少岁,那些70后的程序员都消失了?
    连阿里都在用它处理亿万级数据统计,论其对Java程序员的重要性!
    【源码】HashMap源码及线程非安全分析
    基于框架的RPC通信技术原理解析
    如何写好一份技术简历?
    彻底理解Netty,这一篇文章就够了
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/15114916.html
Copyright © 2011-2022 走看看