单调队列1007 Codeforces Round #219 (Div. 1) 372C. Watching Fireworks is Fun

来源:互联网 发布:网络统考时间 编辑:程序博客网 时间:2024/05/23 10:40

题意:
在一条街上有n个点.之后会有m个烟花点燃
每个烟花有三种属性
ai bi ti
ai代表烟花点燃的位置
ti代表烟花点燃的时间
假设当前人在位置x
那么就会得到一个值bi-|ai-x|
在第0秒的时候,位置是随意的
每秒可以移动<=d的位置
问点燃完m个烟花后得到值得和的最大值
思路:
我们需要求sigma(bi-|ai-x|)->
sigma(bi)-sigma(|ai-x|)
sigma(bi)是已知的
所以我们需要求最小的sigma(|ai-x|)
然后就可以对于位置进行dp
dp[i][j]代表执行第i个事件时在第j位置上最小的和
因为每秒可以移动d个单位
所以假设当前第i个事件和i-1个事件相差一秒
我们就需要求
dp[i][j]=min(dp[i-1][k]+|ai-j|)
Left<=k<=right
left=j-d
Right=j+d
我们找的是最小的dp[i-1][k]
而且每次j移动的时候需要去掉一些dp[i-1][k]
所以这时候就可以对dp[i-1][k]维护一个单调队列
因为i和j太大,所以用滚动数组进行dp
然后就划划水,就A了

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<queue>#include<stack>#include<string>#include<vector>#include<map>#include<set>using namespace std;#define lowbit(x) (x&(-x))typedef long long LL;const int maxn = 150005;const int inf=(1<<28)-1;LL dp[2][maxn];pair<LL,LL>Par[maxn];deque<pair<LL,int> >Que;int main(){    int n,m,d;    scanf("%d%d%d",&n,&m,&d);    LL ans=0;    for(int i=0;i<m;++i)    {        LL x;        scanf("%lld%lld%lld",&Par[i].second,&x,&Par[i].first);        ans+=x;    }    sort(Par,Par+m);    for(int i=1;i<=n;++i) dp[0][i]=abs(i-Par[0].second);    //for(int i=1;i<=n;++i) printf("%lld ",dp[0][i]);printf("\n");    int now=1;    for(int i=1;i<m;++i)    {        LL k=Par[i].first-Par[i-1].first;        k*=d;        LL LastLeft=1;        LL LastRight=min((LL)n,k+1);        //printf("***%lld %lld\n",LastLeft,LastRight);        Que.clear();        for(int j=LastLeft;j<=LastRight;++j)        {            while(!Que.empty()&&Que.back().first>=dp[!now][j])            Que.pop_back();            Que.push_back(make_pair(dp[!now][j],j));        }        for(int j=1;j<=n;++j)        {            LL Left=max(1LL,(LL)j-k);            LL Right=min((LL)n,(LL)j+k);            if(Right!=LastRight)            {                LL tmp=dp[!now][Right];                while(!Que.empty()&&Que.back().first>=tmp)                Que.pop_back();                Que.push_back(make_pair(tmp,Right));            }            while(!Que.empty()&&Que.front().second<Left)            Que.pop_front();            dp[now][j]=abs(Par[i].second-j)+Que.front().first;            LastRight=Right;LastLeft=Left;        }        //for(int j=1;j<=n;++j) printf("%lld ",dp[now][j]);printf("\n");        now=!now;    }    LL res=inf;    for(int i=1;i<=n;++i) res=min(res,dp[!now][i]);    printf("%lld\n",ans-res);    return 0;}
0 0
原创粉丝点击