这道题很不错,首先读入方式有一种跳跃的既视感:
读入Si之后,我们可以直接往后跳Si,可以想到最短路,设序列为a[],我们设n+1是终点如果i+a[i]<=n+1 那么i-->i+a[i] 权值为0 否则i-->n+1 权值为i+a[i]-n注意这可以算是一种非常经典的区间建图的方法下面我们解决调整某个数,我们比划一下就知道,在相邻两点连一条权值为1的无向边即可然后我们可以跑最短路了但是看到n<=1000000是不是感觉dij+heap有点虚?实际上对这个图我们直接宽搜就好了为什么?仔细研究发现,大部分边权值不是1就是0,只有一些点到终点的权值是不和谐的但这有什么关系呢?我们到快到终点的那个点直接计算比较取最优即可1 const inf=1000000007; 2 3 var q,f,d:array[0..1000010] of longint; 4 ans,n,i,h,r:longint; 5 6 function min(a,b:longint):longint; 7 begin 8 if a>b then exit(b) else exit(a); 9 end;10 11 procedure add(x,w:longint);12 begin13 if (x<1) or (x>n+1) then exit;14 while d[x]>inf do15 begin16 d[x]:=w;17 inc(r);18 q[r]:=x;19 if f[x]>n then20 begin21 ans:=min(ans,f[x]-n-1+d[x]);22 exit;23 end;24 x:=f[x];25 end;26 end;27 28 procedure work;29 var x:longint;30 begin31 if f[1]>n then32 begin33 ans:=f[1]-n-1;34 exit;35 end;36 h:=1;37 add(f[1],0);38 while (h<=r) and (d[n+1]>inf) do39 begin40 x:=q[h];41 add(x-1,d[x]+1);42 add(x+1,d[x]+1);43 inc(h);44 end;45 end;46 47 begin48 readln(n);49 for i:=1 to n do50 begin51 read(f[i]);52 f[i]:=f[i]+i+1;53 end;54 ans:=inf;55 fillchar(d,sizeof(d),127);56 work;57 ans:=min(ans,d[n+1]);58 writeln(ans);59 end.