[AtCoder Regular Contest 072] E: Alice in linear land (arc072e)

原题链接
https://arc072.contest.atcoder.jp/tasks/arc072_c

Description

Alice在一个数轴上,一开始她到原点有D的距离(位置正负不论)
给出一个长度为N的正整数序列a
她会按照a从1到N顺次操作,第i次操作的移动距离为a[i],若朝着原点方向移动a[i]的长度(可能跨过原点)会比目前到原点的距离严格更近,那么她就会走,否则不走

现在有Q个询问,每次询问是否能够通过修改第x个数,使得Alice不能到达原点
N,Q<=500000
D,a<=1e9

Solution

思考一下我们是如何暴力的

显然正负没有用,我们只考虑距离
先预处理出做了前i次操作离原点的距离c[i]
设0/1状态 gi,j g i , j 表示站在距离原点为j的位置,后i~n次操作能否到达原点

然而事实上,我们并不需要维护每一个距离的0/1状态
只需要找到一个离原点最近的不能到原点的距离,只要这个距离小于等于当前的距离,那么我们就可以通过修改这一个a使得它走到这个点去,以后就都不能走到原点了

所以我们设 F[i] F [ i ] 表示距离原点最短的经过后i次操作不能到达原点的距离
gi,0...F[i]1=1,gi,F[i]=0 g i , 0... F [ i ] − 1 = 1 , g i , F [ i ] = 0

现在只需要考虑F的转移
从后往前做,每一次前面新加入的一个a[i],因为第i次以后的操作都不能使F[i+1]到达原点了,并且F[i+1]已经是最短的不能到达的距离,那么只要这一个a能够使当前距离更近原点,那么这一个距离就可以到达了,需要找到下一个不能到达原点的距离

可以发现下一个转移到的距离必是 F[i+1]+a[i] F [ i + 1 ] + a [ i ] ,这个位置经过第i次操作刚好走到F[i+1]的位置,然而后i+1次操作又不能走到原点
并且F[i+1]到F[i+1]+a[i]中间的点经过a[i]都会走的比F[i+1]更近,那显然是可以走到原点的

这样就可以通过O(N)的DP做完了

Code

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 500005
using namespace std;
int f[N],c[N],n,m,a[N];
int main()
{
    cin>>n>>m;
    fo(i,1,n) scanf("%d",&a[i]);
    int d=m;
    fo(i,1,n) 
    {
        if(abs(d-a[i])<d) d=abs(d-a[i]);
        c[i]=d;
    }
    f[n+1]=1;
    fod(i,n,1)
    {
        f[i]=f[i+1];
        if(abs(f[i]-a[i])<f[i]) f[i]=f[i]+a[i];
    }
    int q;
    cin>>q;
    c[0]=m;
    fo(i,1,q)
    {
        int x;
        scanf("%d",&x);
        if(c[x-1]>=f[x+1]) printf("YES\n");
        else printf("NO\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值