传送门
http://218.28.19.228/cogs/problem/problem.php?pid=2064
http://218.28.19.228/cogs/problem/problem.php?pid=2065
http://218.28.19.228/cogs/problem/problem.php?pid=2066
T1 爬山
题目大意
给定初始位置,能花费的时间,末了位置,以及每次移动(向上或向下)的最大距离,询问最高能达到多少
题解
我们画画图想一下,其实就是努力向上爬再努力向下爬到达末了位置,时间在规定以内就好,所以我们二分答案就可以啦
枚举ans,⌈ans−ad⌉+⌈ans−bd⌉<=n
向上取整可以有不讨论的技巧,比如说
⌈ans−ad⌉
,就可以写成((ans-a-1)div d)+1
注意二分不要被卡住!
注意二分不要被卡住!
注意二分不要被卡住!
二分真的真的真的真的真的是很容易挂的东西!!!
var
tt,l,r,mid,n,d,a,b:int64;
function check(ans:int64):longint;
begin
tt:=(ans-a-1)div d; inc(tt);
if (n-tt)*d+b>=ans
then exit(1)
else exit(0);
end;
begin
assign(input,'mountain.in'); assign(output,'mountain.out'); reset(input); rewrite(output);
readln(n,d,a,b); dec(n);
l:=a; r:=d*n+a;
while l<r do
begin
mid:=(l+r) div 2;
if check(mid)=1
then l:=mid
else r:=mid-1;
if l+1=r then break;
end;
if check(r)=1 then l:=r;
writeln(l);
close(input); close(output);
end.
T2 学数数
题目大意
给定n个数的序列,它有n∗(n+1)2个子序列,取出每个子序列中的最大值,q次询问小于/等于/大于k的数的个数
题解
这题其实很好想的,但是考试时候我一直写到结束都没处理好二分讨论,没错,又是二分!!!
好吧,我们先说说怎么做
我们发现,取出的数也只是那n个数中的数,只是数的个数有区别,所以我们想办法处理出每个数的个数,其实就相当于每个数的贡献,每个数往两边扩展直到比它大的数出现,就像最大全0子矩阵中的一行一样,我们用单调栈轻松处理,但是我们从数据范围的提示中发现,数中有重复,也就是扩展的时候有相等的,我在考试时想到的是先离散化,处理完再离散化回来,其实不用没有重复的时候是x[k]< x[i]< x[j],重复就把把其中一边带上等号即可了….因为相同的数在同一区间里效果是一样的,和离散化的想法一样就是规定相同的哪个大,一边取等就是直接用它们的数组下标来限定,
查询时二分就好,到底怎么二分查找其实我还不太清楚,因为我不觉得二分讨论会讨论到我写的程度,等我再求教神犇之后再写吧
const
maxn=100050;
var
t,l,r,x,z:array[0..maxn]of longint;
sum,y,ans:array[0..maxn]of int64;
i,j,k:longint;
n,q,len,tt,ll,rr,mid,pp:longint;
ch:char;
procedure sort(l,r:longint);
var i,j,a,b:longint; c:int64;
begin
i:=l; j:=r; a:=x[(l+r) div 2];
repeat
while x[i]<a do inc(i);
while a<x[j] do dec(j);
if not(i>j) then
begin
b:=x[i]; x[i]:=x[j]; x[j]:=b;
c:=y[i]; y[i]:=y[j]; y[j]:=c;
inc(i); dec(j);
end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end;
begin
assign(input,'jxthree.in'); assign(output,'jxthree.out'); reset(input); rewrite(output);
readln(n,q);
for i:=1 to n do
read(x[i]);
readln;
t[1]:=1; l[1]:=1; len:=1; t[0]:=0; x[0]:=maxlongint;
for i:=2 to n do
begin
tt:=0;
for j:=len downto 0 do
if x[i]<x[t[j]]
then begin l[i]:=i-t[j]; tt:=j; break; end
else r[t[j]]:=i-t[j];
len:=tt+1; t[len]:=i;
end;
for i:=1 to len do
r[t[i]]:=n+1-t[i];
for i:=1 to n do
y[i]:=int64(l[i])*int64(r[i]);
sort(1,n); len:=0; x[0]:=-1;
for i:=1 to n do
if x[i]<>x[i-1] then begin inc(len); z[len]:=x[i]; end;
tt:=0;
for i:=1 to n do
begin
if x[i]<>x[i-1] then inc(tt);
inc(ans[tt],y[i]);
end;
sum[0]:=0;
for i:=1 to n do
sum[i]:=sum[i-1]+ans[i];
for i:=1 to q do
begin
readln(ch,k); pp:=0;
if k>z[len] then begin
case ch of
'<':writeln(sum[len]);
'=':writeln(0);
'>':writeln(0);
end;
continue;
end;
ll:=1; rr:=len; j:=0;
while ll<=rr do
begin
mid:=(ll+rr)>>1;
if z[mid]=k then begin
case ch of
'<':writeln(sum[mid-1]);
'=':writeln(ans[mid]);
'>':writeln(sum[len]-sum[mid]);
end;
j:=1; break;
end;
if z[mid]<k
then ll:=mid
else rr:=mid;
inc(pp); if pp=20 then break;
end;
if j=1 then continue;
if (z[ll]=k)or(z[rr]=k) then begin
if z[ll]=k then mid:=ll;
if z[rr]=k then mid:=rr;
case ch of
'<':writeln(sum[mid-1]);
'=':writeln(ans[mid]);
'>':writeln(sum[len]-sum[mid]);
end;
continue;
end;
if k<z[ll]
then dec(ll)
else if k>z[rr] then inc(ll);
case ch of
'<':writeln(sum[ll]);
'=':writeln(0);
'>':writeln(sum[len]-sum[ll]);
end;
end;
close(input); close(output);
end.