F - Watching Fireworks is Fun(单调队列优化dp)

单调队列优化dp一般用在这一次要求的状态时由上一个状态的一个区间转移而来的。然后来看看本题。
题目链接
本来以为重新打一遍代码过不了的,然后一发入魂
在这里插入图片描述

题解:这个题应该不难看出是dp吧(看第二次烟花和看第一次烟花有状态转移关系,假设第一次看烟花的位置是j, 那么第二次看烟花的位置只能是 j-t0 x d到j+t0 x d,其中t0是两次烟花爆炸的时间间隔,d是单位时间人移动的距离)所以就可以得到转移方程是dp[i][j]=dp[i-1][k]+p[i].b+abs(p[i].a-j);(j-t x d<=k<=j+t x d)又因为这样空间会超,不要问我为什么知道这样会超空间,因为我第一发就是超空间,所有这个题就要用滚动数组了。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define ull unsigned long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define bug cout<<"----acac----"<
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 1e6 + 50;
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9+7;
const  double pi=3.141592653589;
ll q[maxn];
ll dp[2][maxn];
struct node
{
    ll a,b,t;
}p[maxn];
int main()
{
    IOS;
    int n,m,d;
    cin>>n>>m>>d;
    for(int i=1;i<=m;i++)
    {
        cin>>p[i].a>>p[i].b>>p[i].t;
    }
    ll time=p[1].t,head=0,tail=0;
    for(int i=1;i<=m;i++)
    {
        if(p[i].t==time)
        {
            for(int j=1;j<=n;j++)
            {
                dp[i%2][j]=dp[(i-1)%2][j]+p[i].b-abs(p[i].a-j);//因为time=p[i].t没有时间可以移动
            }//i%2 与 (i-1)%2 就是滚动数组
        }
        else
        {
            head=0,tail=0;
            ll t0=p[i].t-time;
            time=p[i].t;
            int k=1;
            for(int j=1;j<=n;j++)
            {
                while(k<=n&&k<=j+d*t0)//维护队列的右端点
                {
                    while(tail>head&&dp[(i-1)%2][q[tail-1]]<dp[(i-1)%2][k])tail--;//维护队列的最大值
                    q[tail++]=k++;
                }
                while(tail>head&&q[head]<j-t0*d)//维护队列的左端点
                {
                    head++;
                }
                dp[i%2][j]=dp[(i-1)%2][q[head]]+p[i].b-abs(p[i].a-j);
            }
        }
    }
    ll ans=-lnf;
    for(int i=1;i<=n;i++)
    {
        ans=max(ans,dp[m%2][i]);
    }
    cout<<ans<<endl;
    return 0;
}













你可能感兴趣的:(acm暑训,算法,队列,动态规划)