1049: [HAOI2006]数字序列 - BZOJ

Description

现在我们有一个长度为n的整数序列A。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。但是不希望改变过多的数,也不希望改变的幅度太大。
Input

第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。
Output

第一行一个整数表示最少需要改变多少个数。 第二行一个整数,表示在改变的数最少的情况下,每个数改变的绝对值之和的最小值。
Sample Input
4
5 2 3 5
Sample Output
1
4

【数据范围】
90%的数据n<=6000。
100%的数据n<=35000。
保证所有数列是随机的。

 

这个算法的复杂度真的是O(n^2)吗?怎么我觉得不对呢

和机房的小伙伴讨论之后,觉得这个复杂度应该是O(n^3)的(虽然跑得很快)

先转换一下,b[i]=a[i]-i,然后就是求b的最长不下降了,这样好算代价一些

cost[i]=cost[j]+w(j,i)(f[j]=f[i]-1,j<i)

计算w的时候有一个定理,肯定有一种最优方案是把左半边变成b[j]右半边变成b[i]

证明:http://pan.baidu.com/share/link?uk=2651016602&shareid=1490516411

 1 const

 2     maxn=35010;

 3     inf=1000000000;

 4 var

 5     a,f,b,first,next,last:array[0..maxn]of longint;

 6     g:array[0..maxn]of int64;

 7     n,tot,max:longint;

 8  

 9 procedure insert(x,y:longint);

10 begin

11     inc(tot);

12     last[tot]:=y;

13     next[tot]:=first[x];

14     first[x]:=tot;

15 end;

16  

17 procedure find(x:longint);

18 var

19     l,r,mid:longint;

20 begin

21     l:=1;

22     r:=n;

23     while l<>r do

24       begin

25         mid:=(l+r)>>1;

26         if b[mid]>a[x] then r:=mid

27         else l:=mid+1;

28       end;

29     if max<l then max:=l;

30     f[x]:=l;

31     b[l]:=a[x];

32     insert(l,x);

33 end;

34  

35 procedure init;

36 var

37     i:longint;

38 begin

39     read(n);

40     for i:=1 to n do

41       begin

42         read(a[i]);

43         dec(a[i],i);

44       end;

45     inc(n);

46     a[n]:=inf-1;

47     a[0]:=-inf;

48     for i:=1 to n do

49       b[i]:=inf;

50     insert(0,0);

51 end;

52  

53 function calc(l,r:longint):int64;

54 var

55     i:longint;

56     s:int64;

57 begin

58     s:=0;

59     for i:=l to r do

60       inc(s,abs(a[i]-a[r]));

61     calc:=s;

62     for i:=l to r do

63       begin

64         s:=s-abs(a[i]-a[r])+abs(a[i]-a[l]);

65         if calc>s then calc:=s;

66       end;

67 end;

68  

69 procedure work;

70 var

71     i,j:longint;

72     num:int64;

73 begin

74     for i:=1 to n do

75       begin

76         find(i);

77         g[i]:=inf*inf;

78         j:=first[f[i]-1];

79         while j<>0 do

80           begin

81             if a[last[j]]<=a[i] then

82               begin

83                 num:=calc(last[j],i);

84                 if g[i]>g[last[j]]+num then g[i]:=g[last[j]]+num;

85               end;

86             j:=next[j];

87           end;

88       end;

89     writeln(n-max);

90     write(g[n]);

91 end;

92  

93 begin

94     init;

95     work;

96 end.
View Code

pascal第三(前两名是怎么回事......)

你可能感兴趣的:(ZOJ)