这道题很不错,首先读入方式有一种跳跃的既视感:
读入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 begin 13 if (x<1) or (x>n+1) then exit; 14 while d[x]>inf do 15 begin 16 d[x]:=w; 17 inc(r); 18 q[r]:=x; 19 if f[x]>n then 20 begin 21 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 begin 31 if f[1]>n then 32 begin 33 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) do 39 begin 40 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 begin 48 readln(n); 49 for i:=1 to n do 50 begin 51 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.