[??记录]AT2401 [ARC072C] Alice in linear land

command_block

2021-05-11 21:00:04

Personal

**题意** : 维护一个变量 $X$ ,初始值为 $L$。 给出长度为 $n$ 的指令序列 $A$ 。 依次执行 $A_{1\sim n}$ ,对于 $A_i$ ,令 $X\leftarrow \min\big\{|X-A_i|,x\big\}$。 给出 $q$ 次询问,每次给出 $p$ ,允许对 $A_p$ 进行任意修改,判定能否使得 $A$ 执行完成后 $X$ 不为 $0$。 询问之间**独立**。 $n,q\leq 5\times 10^5$ ,时限$\texttt{2s}$。 ------------ 对于某个操作,可以将操作序列分为 前缀 / 被操作的一个元素 / 后缀 三个部分。 记操作 $A_{1\sim k}$ 执行完后 $X$ 的值为 $X_i$ ,容易预处理。 对于修改 $A_p$ 的操作,先取出 $X_{p-1}$ ,然后通过 $A_p$ ,能(且只能)得到 $[0,X_{p-1}]$ 中的数。 现在问题转化为 : 对于每个后缀,求出是否存在 $[0,X_{p-1}]$ 中的初始值,使得操作结果不为 $0$。 记 $g_{i,x}$ 表示初始值为 $x$ 时,执行 $A_{i\sim n}$ 会不会得到 $0$。 能列出如下转移 : $$ g_{i,x}= \begin{cases} g_{i+1,x}&(x\leq A_i/2)\\ g_{i+1,A_i-x}&(A_i/2< x\leq A_i)\\ g_{i+1,x-A_i}&(A_i\leq x) \end{cases} $$ 整个 $\rm DP$ 的复杂度是 $O(nL)$ ,无法通过。 注意到 $\rm DP$ 的决策是固定的(转移 $\rm DAG$ 是一个内向树),没有“最优化”成分。 这些状态之间的贡献关系并不紧密,尝试对状态进行简化。 我们在询问中需要判定 $g_{p+1,0\sim X_{p-1}}$ 中是否存在 $0$。 可以只关心 $g_{p+1,\_}$ 中最靠前的一个 $0$。 记 $f_i$ 为通过 $A_{i,n}$ 不会变为 $0$ 的最小的数。 有转移 : $$ f_i= \begin{cases} f_{i+1}&(f_{i+1}\leq A_i/2)\\ f_{i+1}+A_i&(f_{i+1}>A_i/2) \end{cases} $$ (不难证明只有最小值会转移到最小值) 复杂度 $O(n)$。 ```cpp #include<algorithm> #include<cstdio> #define MaxN 500500 using namespace std; const int mod=1000000007; int n,q,x[MaxN],a[MaxN],f[MaxN]; int main() { scanf("%d%d",&n,&x[0]); for (int i=1;i<=n;i++){ scanf("%d",&a[i]); x[i]=min(x[i-1],x[i-1]>a[i] ? x[i-1]-a[i] : a[i]-x[i-1]); } f[n+1]=1; for (int i=n;i;i--){ } f[i]=f[i+1]*2>a[i] ? f[i+1]+a[i] : f[i+1]; scanf("%d",&q); for (int i=1,p;i<=q;i++){ scanf("%d",&p); puts(x[p-1]>=f[p+1] ? "YES" : "NO"); } return 0; } ```