[CF1523H]Hopping Around the Array

Posted Tan_tan_tann

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1523H]Hopping Around the Array相关的知识,希望对你有一定的参考价值。

Hopping Around the Array

题解

**卡常题。

我们可以先将删除一个格子的操作看成用代价 0 0 0跳过一个格子,跳到 x + a x x+a_{x} x+ax视作代价为 1 1 1的跳跃。

由于 k k k值较小,我们可以先设计一个dp,令 d p i , j , k dp_{i,j,k} dpi,j,k表示从点 i i i出发进行 j j j次代价为 1 1 1的跳跃与 k k k次代价为 0 0 0的跳跃所能到达的最远的。
很明显,如果我们要往下一次跳跃转移的话我们肯定会先找到 [ i , d p i , j , k ] [i,dp_{i,j,k}] [i,dpi,j,k]之间 a x + x a_{x}+x ax+x最大的点进行转移。
但它总的跳跃次数会特别大,时间复杂度 O ( ( n + q ) n k 2 ) O\\left((n+q)n k^2\\right) O((n+q)nk2),明显会T掉,空间也会爆掉,我们考虑如何优化。

我们可以通过倍增进行维护。
可以证明,它每次都会跳跃到 a x + x a_{x}+x ax+x最大的一个点。
因为在这一次跳跃中,没有点能比这个点在下一次跳得更远的点,而这个点可以使下一次的 a x + x a_{x}+x ax+x尽可能大,所以在相同的跳跃次数中,它一定可以使终点尽可能地远。
所以我们下一次转移只需要从 a x + x a_{x}+x ax+x最大的点转移过来即可,每个点的转移点都是固定的。
我们将原 d p dp dp的定义改成 d p i , j , k dp_{i,j,k} dpi,j,k表示从点 i i i出发,经过 2 j 2^j 2j次代价为 1 1 1的跳跃, k k k次代价为 0 0 0的跳跃所能到达的最远的点。
转移方程式容易得到,记 c a l c ( l , r ) calc(l,r) calc(l,r)表示区间 [ l , r ] [l,r] [l,r] a x + x a_{x}+x ax+x最大的点的 x x x
d p i , j , k + Δ = max ⁡ l = 0 k ( d p c a l c ( i , d p i , j − 1 , l ) , j − 1 , k − l ) + Δ dp_{i,j,k+\\Delta}=\\max_{l=0}^{k}(dp_{calc(i,dp_{i,j-1,l}),j-1,k-l})+\\Delta dpi,j,k+Δ=l=0maxk(dpcalc(i,dpi,j1,l),j1,kl)+Δ

而我们从一个起点开始到一个终点的最小步数可以像倍增求 l c a lca lca一样求,从这个起点开始倍增。
我们设 A k A_{k} Ak表示在进行了 x x x次花费为 1 1 1的操作, k k k次花费为 0 0 0的操作后,我们能走到的最远点。
我们每要多走 2 j 2^j 2j步时有转移式:
A k = max ⁡ i = 0 k ( d p A i , j , k − i ) A_{k}=\\max_{i=0}^{k}(dp_{A_{i},j,k-i}) Ak=i=0maxk(dpAi,j,ki)
我们像求 l c a lca lca一样,找到它最多走多少步不会超过终点,那之后再走一步就是走到终点的最小步数。

有了这种想法,我们很容易发现对于很多个的询问这种做法也是适用的,它单次询问的时间复杂度是较小的时间复杂度确实很小,但常数不小
于是我们只需要先处理出 d p dp dp数组,再对单个询问倍增求出答案即可。
对于 c a l c ( l , r ) calc(l,r) calc(l,r)函数,我们可以通过st表进行维护。

时间复杂度 O ( ( n + q ) k 2 l o g   n ) O\\left((n+q)k^2log\\,n\\right) O((n+q)k2logn)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 40005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int zero=500;
const LL jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,q,a[MAXN],st[MAXN][20],f[MAXN][35][20],lg[MAXN],A[35],tmp[35],B[35];
int Max(const int x,const int y){return x+a[x]>y+a[y]?x:y;}
inline int query(int l,int r){if(l>r)return 0;r=min(r,n);const int k=lg[r-l+1];return Max(st[l][k],st[r-(1<<k)+1][k]);}
signed main(){
	read(n);read(q);lg[1]=0;
	for(reg int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(reg int i=1;i<=n;i++)read(a[i]);
	for(reg int i=1;i<=n;i++)st[i][0]=i;
	for(reg int i=1;i<=lg[n];i++)
		for(reg int j=1;j<=n-(1<<i)+1;j++)
			st[j][i]=Max(st[j][i-1],st[j+(1<<i[CF1038F]Wrap Around[AC自动机+dp]

CF1550F Jumping Around

[CF1550F]Jumping Around

UVa821 Page Hopping (Floyd)

Hopping Rabbit

UVa 10801 - Lift Hopping