【題目大意】
中文題面。
需要注意的是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+單調隊列