Contest-hunter 暑假送温暖 SRM01
一直找不到好的题去做...于是想到了srm...回来补题...QAQ
从srm01补起
A
题意:n个数,排成一列,刚开始都是1,如果左右相等就可以合并,问最后的数列长什么样。
思路:比赛的时候直接敲了个 一直log2 直到为0,觉得应该是100的...于是炸到了90.
比完赛懒得调就没去理,回来补的时候发现是p的trunc有点问题哇...以后都打成trunc(x+0.000001) 出错率会低一点QAQ
1 var n,s:longint; 2 begin 3 read(n); 4 repeat 5 s:=trunc(ln(n)/ln(2)+0.00001); 6 write(s+1,' '); 7 n:=n-(1 << s); 8 until n=0; 9 end.
B
题意:有m升油,n个数,可以用一升油数某一个数+1,再给一个mx 然后给 v1 v2 求 (v1*达到mx的数的个数+v2*整个数列的最小值)最大化。
思路:比赛的时候想的是拿部分分,然后弄不出来,然后觉得是二分,敲不出来,就拿到了10分。
补题的时候有一个新的思路,枚举达到mx的数的个数,然后再二分最小值。
然后check就贪心的弄,设达到mx的数的个数为num,二分到的最小值为x
然后贪心算需要的油就可以check了,但是这样要多一个n的复杂度。
显然o(n^2 logn)的复杂度是要tle的。
想想优化,由于贪心,所以已经先把原数列排序了,辣么就满足的单调性。
满足单调性就可以二分
所以求排序后的数列的前缀和,然后在二分里在套一个二分就好了
复杂度 o(n logn ^2)
1 var a,b,c,sum:array[0..200000]of int64; 2 n,mx,v1,v2:int64; 3 have,z:int64; 4 l,r,m:longint; 5 ans,num,ansmin,ansnum:int64; 6 i,j:longint; 7 procedure qs(l,r:longint); 8 var i,j,t,m:longint; 9 begin 10 i:=l; 11 j:=r; 12 m:=a[(l+r)>>1]; 13 repeat 14 while a[i]>m do inc(i); 15 while a[j]<m do dec(j); 16 if i<=j then 17 begin 18 t:=a[i];a[i]:=a[j];a[j]:=t; 19 t:=c[i];c[i]:=c[j];c[j]:=t; 20 inc(i); 21 dec(j); 22 end; 23 until i>j; 24 if l<j then qs(l,j); 25 if i<r then qs(i,r); 26 end; 27 function find(x:longint):longint; 28 var l,r,m:longint; 29 begin 30 l:=num+1; 31 r:=n; 32 while l<=r do 33 begin 34 m:=(l+r) >>1; 35 if a[m]>x then l:=m+1 else r:=m-1; 36 end; 37 exit(l); 38 end; 39 function check(x:longint):boolean; 40 var i:longint; 41 need:int64; 42 begin 43 need:=z; 44 i:=find(x); 45 inc(need,x*(n-i+1)-(sum[n]-sum[i-1])); 46 if need>have then exit(false) else exit(true); 47 end; 48 begin 49 read(n,mx,v1,v2,have); 50 for i:=1 to n do 51 begin 52 read(a[i]); 53 b[i]:=a[i]; 54 c[i]:=i; 55 end; 56 qs(1,n); 57 for i:=1 to n do 58 sum[i]:=sum[i-1]+a[i]; 59 for i:=1 to n do 60 begin 61 num:=i; 62 z:=mx*num-sum[num]; 63 if z>=have then continue; 64 l:=1; 65 r:=mx; 66 while l<r do 67 begin 68 m:=(l+r+1)>>1; 69 if check(m) then l:=m else r:=m-1; 70 end; 71 if ans<num*v1+l*v2 then 72 begin 73 ans:=num*v1+l*v2; 74 ansnum:=num; 75 ansmin:=l; 76 end; 77 end; 78 writeln(ans); 79 for i:=1 to ansnum do 80 b[c[i]]:=mx; 81 for i:=1 to n do 82 if b[i]<ansmin then write(ansmin,' ')else write(b[i],' '); 83 writeln; 84 end.
C
题意:一个数列,支持两个操作,1.L~R 加上x 2.查询当前序列,如果从任意一个位置开始,两边严格递减的最大长度。
思路:比赛的时候完全没思路,暴力都不会打。
补题觉得可以线段树弄,每次维护区间最大长度,左边的值,右边的值,然后乱维护....QAQ
结果不会打。所以pass掉吧...