bzoj2259

这道题很不错,首先读入方式有一种跳跃的既视感:
读入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.
View Code
原文地址:https://www.cnblogs.com/phile/p/4472951.html