UESTC1132 酱神赏花 【DP+单调队列】

【题目大意】

中文题面。

需要注意的是AI,BI,TI和题面里的输入顺序不同

【解题思路】

由于bi是常数,所以可以用Σb来减去答案即可。

所以实际上我们维护的是|x-ai|的最小值

状态定义:dp[i][j]表示第j时刻(注意是时刻不是时间,此处的j只表明花出现的顺序而不关心花出现的具体时间)人在i位置时所对应的|x-ai|的最小值

考虑转移方程:dp[i][j]=min(dp[k][j-1]+|i-flower[j]|)其中k满足i-Δt*d<=k<=i+Δt*d(Δt=这一时刻的时间减去上一时刻的时间)

由于|i-flower[j]|与min函数的主体k无关,所以该部分可以从min中取出

所以转移方程转化为->dp[i][j]=min(dp[k][j-1])+|i-flower[j]|

其中min部分可以使用单调队列进行处理

最后枚举终点,求出答案

【代码】

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstdlib>
//#include<conio.h>
#include<iomanip>
#define LL long long
//#define LOCAL
using namespace std;

const int N=100011;
const LL INF=2139062143;
LL n,m,d,sigma_s;
LL dp[N][101];
LL ans;
int head,tail;

int tim=0;

struct Flower{
	int t;
	int f;
}delta[N];

bool cmp(const Flower &A,const Flower &B){
	return A.t<B.t;
}

struct Handrum{
	int q[N];
	bool exist[N];
	
	void Insert(LL x,LL s){
		while (head<=tail&&dp[q[tail]][s]>=dp[x][s]) exist[q[tail--]]=false;
        q[++tail]=x;
        exist[x]=true;
	}
	
	void Clear(){
		head=0;
        tail=-1;
		memset(q,0,sizeof(q));
		memset(exist,false,sizeof(exist));
	}
	
	void Delete(LL x){
		if (exist[x]) head++;
	}
	

}que;

int main(){
#ifdef LOCAL
    freopen("UESTC1132.in","r",stdin);
#endif
    que.Clear();
    ans=INF;
    sigma_s=0;
    scanf("%lld%lld%lld",&n,&m,&d);
    for (int i=1;i<=m;++i){
    	LL pos,value;
    	scanf("%lld%lld%lld",&pos,&value,&delta[i].t);
    	delta[i].f=pos;
    	sigma_s+=value;
	}
	sort(delta+1,delta+m+1,cmp);
	for (int i=1;i<=n;++i){
		dp[i][1]=abs(i-delta[1].f);
	}
	for (int i=2;i<=m;++i){
		que.Clear();
		LL tmp=delta[i].t-delta[i-1].t;
		LL len=tmp*d;
		for (int j=1;j<=min(len,n);++j) que.Insert(j,i-1);
		for (int j=1;j<=n;++j){
			if (j+len<=n) que.Insert(j+len,i-1);
			if (j-len>1) que.Delete(j-len-1);
			dp[j][i]=dp[que.q[head]][i-1]+abs(j-delta[i].f);

		}
		
	}
	for (int i=1;i<=n;++i) ans=min(ans,dp[i][m]);
	printf("%lld\n",sigma_s-ans);
	return 0;
}

【总结】

DP+单调队列


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值