Codeforces 1523H. Hopping Around the Array 题解
题目链接:H. Hopping Around the Array
题目大意:给定一个序列 \(a_1,a_2,\dots,a_n\),在第 \(i\) 个点可以一步走到 \([i,i+a_i]\) 中的任何一个点,多次询问,每一次从 \(l\) 出发,你可以删掉不超过 \(k\) 的点,将剩下的点重标号,使得到达 \(r\) 的步数最少。
\(n\leq 2\times 10^4\),\(k\leq 30\)。
题解:首先考虑没有删除点应当怎么做,显然我们从第 \(i\) 个点出发,我们可以到达的点是 \([i,i+a_i]\),那么我们假设我们下一步走到的点为 \(j(j\in [i,i+a_i])\),那么 \(j\) 一定满足 \(\forall i\leq k\leq i+a_i,j+a_j\geq k+a_k\)。
如果我们删点,那么假设在第 \(i\) 个点,删除了 \(x\) 个点,那么显然会走到 \(i+a_i+x\),否则的话就没有必要删这么多。
那么我们就很容易设计一个状态,设 \(f_{i,k,j}\) 表示从 \(j\) 出发,走 \(2^i\) 步,可以删除不超过 \(k\) 个点可以走到的最远点。
然后转移的时候我们直接暴力枚举 \(k_1,k_2\) 将 \(\max_{l=j}^{f_{i,k_1,j}} f_{i,k_2,l}\) 的答案贡献到 \(f_{i+1,k_1+k_2,j}\) 上,这部分可以通过数据结构来优化。
接下来把所有的询问离线一起处理,设 \(ans_{t,i,j}\) 表示第 \(i\) 个询问,删除 \(j\) 个点,在考虑 \(\geq 2^t\) 步的所有的情况下所能够到达的最靠右的不超过 \(r_i\) 的点是什么(由我们在题解开头给出的结论,容易得到这样贪心是正确的),初始的时候是 \(\forall 0\leq j\leq k_i, ans_{\log n,i,j}=l_i\)。
然后这一部分中间的转移我们同样可以通过数据结构优化。
时间复杂度为:\(O(nk\log^2 n + nk^2\log n)\)
代码:
#include <cstdio>
#include <algorithm>
const int Maxn=20000;
const int Maxd=17;
const int Maxk=30;
int n,q;
int nxt[Maxd+1][Maxk+1][Maxn+1];
int f_max[Maxk+1][Maxd+1][Maxn+1];
int a[Maxn+1];
int log_2[Maxn+1];
void init(){
log_2[0]=-1;
for(int i=1;i<=Maxn;i++){
log_2[i]=log_2[i>>1]+1;
}
}
int query_max(int k,int l,int r){
int d=log_2[r-l+1];
return std::max(f_max[k][d][l],f_max[k][d][r-(1<<d)+1]);
}
int ans[Maxn+1];
int pos_r[Maxn+1][Maxk+1];
struct Question{
int l,r,k;
}qu[Maxn+1];
int main(){
init();
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
for(int j=0;j<=Maxk;j++){
nxt[0][j][i]=std::min(i+a[i]+j,n);
}
}
for(int i=1;i<=17;i++){
for(int j=1;j<=n;j++){
for(int k=0;k<=Maxk;k++){
f_max[k][0][j]=nxt[i-1][k][j];
}
}
for(int k=0;k<=Maxk;k++){
for(int j=1;(1<<j)<=n;j++){
for(int l=1;l+(1<<j)-1<=n;l++){
f_max[k][j][l]=std::max(f_max[k][j-1][l],f_max[k][j-1][l+(1<<(j-1))]);
}
}
}
for(int k_1=0;k_1<=Maxk;k_1++){
for(int k_2=0;k_1+k_2<=Maxk;k_2++){
for(int j=1;j<=n;j++){
nxt[i][k_1+k_2][j]=std::max(nxt[i][k_1+k_2][j],query_max(k_2,j,nxt[i-1][k_1][j]));
}
}
}
}
for(int i=1;i<=q;i++){
scanf("%d%d%d",&qu[i].l,&qu[i].r,&qu[i].k);
for(int j=0;j<=qu[i].k;j++){
pos_r[i][j]=qu[i].l;
}
if(qu[i].l==qu[i].r){
ans[i]=-1;
continue;
}
}
for(int i=17;i>=0;i--){
for(int j=1;j<=n;j++){
for(int k=0;k<=Maxk;k++){
f_max[k][0][j]=nxt[i][k][j];
}
}
for(int k=0;k<=Maxk;k++){
for(int j=1;(1<<j)<=n;j++){
for(int l=1;l+(1<<j)-1<=n;l++){
f_max[k][j][l]=std::max(f_max[k][j-1][l],f_max[k][j-1][l+(1<<(j-1))]);
}
}
}
for(int j=1;j<=q;j++){
if(ans[j]==-1){
continue;
}
static int np_r[Maxk+5];
for(int k=0;k<=qu[j].k;k++){
np_r[k]=0;
}
for(int k_1=0;k_1<=qu[j].k;k_1++){
for(int k_2=0;k_1+k_2<=qu[j].k;k_2++){
np_r[k_1+k_2]=std::max(np_r[k_1+k_2],query_max(k_2,qu[j].l,pos_r[j][k_1]));
}
}
if(np_r[qu[j].k]<qu[j].r){
ans[j]+=(1<<i);
for(int k=0;k<=qu[j].k;k++){
pos_r[j][k]=np_r[k];
}
}
}
}
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]+1);
}
return 0;
}
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。