SOJ4513: 先锋看烟花 单调队列优化DP

来源:互联网 发布:淘宝店招图片尺寸 编辑:程序博客网 时间:2024/04/26 06:36

题目链接:http://acm.scu.edu.cn/soj/problem.action?id=4513

这是我当初非常自豪,没看题解搞了一个中午就搞出来的题,不过吃了不写题解的亏,现在看自己AC的代码已经和看别人的没什么区别了。


这题数据量很大,要用滚动数组优化空间。

dp[2][maxn]第一维存的是时间,第二维存的是地点,数组中的数表示到达该时该地的最大幸福度。先锋有移动范围d*s,因此用单调队列存入i-d*s到i+d*s范围内上个时间点所有能移动到目前点i的所有幸福度,队首即为最大幸福度,这样每一次状态转移都是O(1)的。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long ll;const int N=150001;ll n,m,d,dp[2][N],a[N],b[N],t[N],q[N*2];//(1<=n<=150000),m(1<=m<=300),d(1<=d<=n)ll fabs(ll& a,ll& b){    return a>b?a-b:b-a;}int main(){    //freopen("D://data.txt","r",stdin);    ios::sync_with_stdio(0);    int T;    cin>>T;    while(T--){        cin>>n>>m>>d;        for(ll i=0;i<m;i++)            cin>>a[i]>>b[i]>>t[i];        ll i=0;        while(i==0||t[i]==t[i-1]){            ll k=i%2;            for(ll j=1;j<=n;j++){                if(!i)dp[k][j]=b[i]-fabs(a[i],j);                else dp[k][j]=dp[!k][j]+b[i]-fabs(a[i],j);            }            i++;if(i==m)break;        }        for(;i<m;i++){            ll k=i%2;            ll s=(t[i]-t[i-1])*d;            int head=0,tail=0;            q[tail++]=1;            if(1+s<=n){                for(int x=1;x<s;x++){                    while(dp[!k][1+x]>dp[!k][q[tail-1]]&&tail>head) tail--;                    q[tail++]=1+x;                }            }            else{                for(int x=1;x<=n-1;x++){                    while(dp[!k][1+x]>dp[!k][q[tail-1]]&&tail>head) tail--;                    q[tail++]=1+x;                }            }            for(ll j=1;j<=n;j++){                while(q[head]<j-s) head++;                if(j+s<=n){                    while(dp[!k][j+s]>dp[!k][q[tail-1]]&&tail>head) tail--;                    q[tail++]=j+s;                }                dp[k][j]=dp[!k][q[head]]+b[i]-fabs(a[i],j);            }        }        ll maxans=-1e18;        ll h=(m-1)%2;        for(ll j=1;j<=n;j++) maxans=max(dp[h][j],maxans);        cout<<maxans<<endl;    }    return 0;}


0 0
原创粉丝点击