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

来源:互联网 发布:js点击切换图片 编辑:程序博客网 时间:2024/05/01 11:17

【题目大意】

中文题面。

需要注意的是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 LOCALusing 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 0
原创粉丝点击