CodeForces 372C :Watching Fireworks is Fun DP + 单调队列

传送门

题目描述

给出N个位子,排成一列,现在有M个烟花,每秒人的速度d,每个烟花有三个元素:a,b,t,表示在时刻t会绽放,如果我们在位子x观看到了的话,会获得b-abs(a-x)的欢乐值(可能为负而且所有烟花都必须观看);初始的时候可以在任何位子,问最高获得多少欢乐值。

分析

看完大概就知道需要DP搞一波
状态转移方程也比较好写
f[i][j] = max(f[i - 1][k] + b[i] - |a[i] - x|);

然后我们把b[i]提出来,可以转换成了求 |a[i] - x|的最小值。
k的范围应该是在x - dt * d ~ x + dt *d 之间,所以我们需要从1 - n跑一次,n - 1跑一次,每次记录一半区间内的最值

需要注意的是,[300][150000]的空间是明显开不下的,但是我们当前的状态仅需要上一维的状态进行状态转移,所以可以用类似于滚动数组的思想来优化空间

代码

#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 152000;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll f[N];
ll back[N];
ll q[N];
ll a[N],b[N],t[N];
ll sum;
ll d;
int n,m;

int main(){
    
    
    read(n),read(m),read(d);
    for(int i = 1;i <= m;i++){
    
    
    	read(a[i]),read(b[i]),read(t[i]);
    	sum += b[i];
    } 
    for(int i = 1;i <= n;i++) f[i] = abs(i - a[1]);
    for(int i = 2;i <= m;i++){
    
    
    	ll dt = t[i] - t[i - 1];
    	memcpy(back,f,sizeof f);
    	memset(f,0x3f,sizeof f);
    	int hh = 1,tt = 0;
    	for(int j = 1;j <= n;j++){
    
    
    		while(hh <= tt && q[hh] < j - dt * d) hh++;
    		while(hh <= tt && back[q[tt]] > back[j]) tt--;
    		q[++tt] = j;
    		f[j] = min(f[j],back[q[hh]] + abs(a[i] - j));
    	}
    	hh = 1,tt = 0;
    	for(int j = n;j;j--){
    
    
    		while(hh <= tt && q[hh] > j + dt * d) hh++;
    		while(hh <= tt && back[q[tt]] > back[j]) tt--;
    		q[++tt] = j;
    		f[j] = min(f[j],back[q[hh]] + abs(a[i] - j));
    	}
    }
    ll ans = 0x3f3f3f3f3f3f3f3f;
    for(int i = 1;i <= n;i++) ans = min(ans,f[i]);
   	dl(sum - ans);
   	return 0;
}

/**
*  ┏┓   ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃       ┃
* ┃   ━   ┃ ++ + + +
*  ████━████+
*  ◥██◤ ◥██◤ +
* ┃   ┻   ┃
* ┃       ┃ + +
* ┗━┓   ┏━┛
*   ┃   ┃ + + + +Code is far away from  
*   ┃   ┃ + bug with the animal protecting
*   ┃    ┗━━━┓ 神兽保佑,代码无bug 
*   ┃        ┣┓
*    ┃        ┏┛
*     ┗┓┓┏━┳┓┏┛ + + + +
*    ┃┫┫ ┃┫┫
*    ┗┻┛ ┗┻┛+ + + +
*/

猜你喜欢

转载自blog.csdn.net/tlyzxc/article/details/113249426