第一题:在数列中选不同的k对数,使绝对值之差总和最小
80分:排序后,每个位置记个指针向后移,每次用堆选取各位置与其对应指针的差之中的最小值,保证堆中只有n-1个元素。
时间复杂度:o(klogn)
100分:二分最大差值,每次用两个指针检验在不超过差值的情况下能有几对数,找到对数刚好大于k,则统计小于这个差值的对数和,然后剩余的采用此差值。
时间复杂度:o(nlogn+nlogdifference)var n,k:int64;
ans:int64;
a:array[1..1000000]of longint;
s:array[0..1000000]of int64;
procedure inf;
begin
assign(input,'mark.in');reset(input);
assign(output,'mark.out');rewrite(output)
end;
procedure ouf;
begin
close(input);close(output)
end;
procedure qsort(l,r:longint);
var i,j,x,c:longint;
begin
i:=l;j:=r;x:=a[(l+r)>>1];
repeat
while a[i]<x do inc(i);
while x<a[j] do dec(j);
if not(i>j) then begin
c:=a[i];a[i]:=a[j];a[j]:=c;
inc(i);dec(j)
end
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j)
end;
function check(mid:int64 ): boolean;
var i,j,tot:int64;
begin
i:=1;j:=1;tot:=0;
while i<=n do begin
while (a[j]-a[i]<=mid)and(j<n) do inc(j);
if a[j]-a[i]>mid then dec(j);
tot:=tot+j-i;
inc(i)
end;
if tot>k then exit(true) else exit(false)
end;
procedure init;
var i,j:longint;
l,r,mid:int64;
begin
readln(n,k);
for i:=1 to n do read(a[i]);
qsort(1,n);
s[0]:=0;
for i:=1 to n do s[i]:=s[i-1]+a[i];
l:=0;r:=maxlongint;
while l<=r do begin
mid:=(l+r)>>1;
if check(mid) then r:=mid-1 else l:=mid+1
end;
i:=1;j:=1;ans:=0;
while i<=n do begin
while (a[j]-a[i]<=l-1)and(j<n) do inc(j);
if (a[j]-a[i]>l) then dec(j);
k:=k-(j-i);
mid:=a[i];
mid:=mid*(j-i);
ans:=ans+(s[j]-s[i]-mid);
inc(i)
end;
if k<>0 then begin
ans:=ans+k*l
end;
writeln(ans)
end;
begin
inf;
init;
ouf
end.
第二题:最优比率生成树
二分+kruscal不行
要用迭代+prim
所谓迭代与牛顿迭代求零点很像,取一个ans,检验与二分相同,不满足,此时,ans新的值为此ans求出的比例
继续在此基础上迭代。const eps=1e-5;
var ans,tot:real;
v:array[1..1000]of boolean;
p:array[1..1000]of longint;
z,x,y,dis:array[1..1000]of real;
c,d,f:array[1..1000,1..1000]of real;
n:longint;
procedure inf;
begin
assign(input,'build.in');reset(input);
assign(output,'build.out');rewrite(output)
end;
procedure ouf;
begin
close(input);close(output)
end;
function check(var ans:real ): real;
var x,i,j,mini:longint;
tot,min,sum1,sum2:real;
begin
fillchar(f,sizeof(f),0);
fillchar(v,sizeof(v),true);
fillchar(dis,sizeof(dis),127);
fillchar(p,sizeof(p),0);
for i:=1 to n-1 do
for j:=i+1 to n do begin
f[i,j]:=c[i,j]-d[i,j]*ans;
f[j,i]:=f[i,j]
end;
v[1]:=false;mini:=1;dis[1]:=0;
tot:=0;min:=0;ans:=0;
sum1:=0;sum2:=0;
while mini<>0 do begin
tot:=tot+min;x:=mini;v[x]:=false;
for i:=1 to n do
if v[i] then begin
if f[x,i]<dis[i] then begin dis[i]:=f[x,i];p[i]:=x end;
end;
min:=maxlongint;mini:=0;
for i:=1 to n do
if v[i] then begin
if dis[i]<min then begin
min:=dis[i];mini:=i
end
end;
if mini<>0 then begin
sum1:=sum1+c[p[mini],mini];
sum2:=sum2+d[p[mini],mini]
end
end;
ans:=sum1/sum2;
exit(tot)
end;
function dist(i,j:longint ): real;
begin
exit(sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j])))
end;
procedure init;
var i,j:longint;
begin
readln(n);
if n=0 then exit;
for i:=1 to n do begin
readln(x[i],y[i],z[i])
end;
fillchar(c,sizeof(c),0);fillchar(d,sizeof(d),0);
for i:=1 to n-1 do
for j:=i+1 to n do begin
c[i,j]:=abs(z[i]-z[j]);
c[j,i]:=c[i,j];
d[i,j]:=dist(i,j);
d[j,i]:=d[i,j]
end;
ans:=1<<20;tot:=check(ans);
while abs(tot)>eps do begin
tot:=check(ans)
end;
writeln(ans:0:3)
end;
begin
inf;
while not seekeof do init;
ouf
end.
第三题:对一段区间or,and
询问xor和50分:按位建立线段树,若or一个数某一位为1则将该区间该位改为1,and同理。
100分:and是满足区间加法的,or在奇数区间满足,而在偶数区间分析可知某位为0无影响,为一则此位最后为0,所以相当于and其各位取反。
处理标记时要开两个标记域,统一先下放and标记,为维护先后关系,放and标记时,or标记要同时and为了纪念我的18棵线段树,50分也贴一贴
var high,n,m1,m,ans:longint;
t,s:array[1..18,1..524288]of longint;
procedure inf;
begin
assign(input,'bit.in');reset(input);
assign(output,'bit.ans');rewrite(output)
end;
procedure ouf;
begin
close(input);close(output)
end;
procedure pushdown(j,x:longint);
var i,p,nx:longint;
begin
p:=m1;
for i:=high downto 1 do begin
p:=p>>1;
if t[j,x>>i]<>-1 then begin
nx:=x>>i;
s[j,nx<<1]:=t[j,nx]*p; t[j,nx<<1]:=t[j,nx];
s[j,nx<<1+1]:=t[j,nx]*p;t[j,nx<<1+1]:=t[j,nx];
t[j,nx]:=-1
end
end
end;
procedure updata(j,x:longint);
begin
while x<>0 do begin
s[j,x]:=s[j,x<<1]+s[j,x<<1+1];
x:=x>>1
end
end;
procedure change(j,l,r,w:longint);
var ll,rr,p:longint;
begin
l:=l+m1-1;r:=r+m1+1;
ll:=l>>1;rr:=r>>1;
pushdown(j,l);pushdown(j,r);
p:=1;
while not(l xor r=1) do begin
if l and 1=0 then begin s[j,l+1]:=w*p;t[j,l+1]:=w end;
if r and 1=1 then begin s[j,r-1]:=w*p;t[j,r-1]:=w end;
l:=l>>1;r:=r>>1;p:=p<<1
end;
updata(j,ll);updata(j,rr)
end;
function ask(j,l,r:longint ): longint;
begin
l:=l+m1-1;r:=r+m1+1;ask:=0;
pushdown(j,l);pushdown(j,r);
while not (l xor r=1) do begin
if l and 1=0 then ask:=ask+s[j,l+1];
if r and 1=1 then ask:=ask+s[j,r-1];
l:=l>>1;r:=r>>1
end
end;
procedure origin;
var j,i:longint;
begin
m1:=1;high:=0;
while m1<=n+2 do begin
m1:=m1<<1;
inc(high)
end;
for j:=1 to 18 do
for i:=0 to m1+m1 do t[j,i]:=-1;
fillchar(s,sizeof(s),0);
end;
procedure init;
var ch,i,j,k,l,r:longint;
begin
readln(n,m);
origin;
for i:=1 to n do begin
read(k);
for j:=1 to 18 do
if (k>>(j-1)) and 1=1 then begin
s[j,i+m1]:=1;
updata(j,(i+m1)>>1)
end
end;
for i:=1 to m do begin
read(ch);
if ch=1 then begin
readln(l,r,k);
for j:=1 to 18 do
if (k>>(j-1)) and 1=0 then change(j,l,r,0)
end
else if ch=2 then begin
readln(l,r,k);
for j:=1 to 18 do
if (k>>(j-1)) and 1=1 then change(j,l,r,1)
end
else begin
readln(l,r);
ans:=0;
for j:=1 to 18 do
if ask(j,l,r) and 1=1 then ans:=ans or (1<<(j-1));
writeln(ans)
end
end;
end;
begin
inf;
init;
ouf
end.
100分:
const maxk=1<<31-1;
var t:array[1..2,1..524288]of longint;
d:array[1..524288]of longint;
ans,m1,high,n,m:longint;
procedure inf;
begin
assign(input,'bit.in');reset(input);
assign(output,'bit.out');rewrite(output)
end;
procedure ouf;
begin
close(input);close(output)
end;
procedure origin;
var i:longint;
begin
m1:=1;high:=0;
while m1<=n+2 do begin
m1:=m1<<1;inc(high)
end;
for i:=1 to m1<<1 do t[1,i]:=maxk
end;
procedure put_and(k,x:longint);
begin
d[x]:=d[x] and k;
t[1,x]:=t[1,x] and k;
t[2,x]:=t[2,x] and k
end;
procedure put_or(k,x:longint);
begin
d[x]:=d[x] and (k xor maxk);
t[2,x]:=t[2,x] or k
end;
procedure pushdown(x:longint);
var i,nx,k:longint;
begin
for i:=high downto 2 do begin
nx:=x>>i;
if (t[1,nx]<>maxk) then begin
put_and(t[1,nx],nx<<1);put_and(t[1,nx],nx<<1+1);
end;
if (t[2,nx]<>0) then begin
put_or(t[2,nx],nx<<1);put_or(t[2,nx],nx<<1+1);
end;
t[1,nx]:=maxk;t[2,nx]:=0
end;
nx:=x>>1;
if t[1,nx]<>maxk then begin
d[nx<<1]:=d[nx<<1] and t[1,nx];
d[nx<<1+1]:=d[nx<<1+1] and t[1,nx];
end;
if t[2,nx]<>0 then begin
d[nx<<1]:=d[nx<<1] or t[2,nx];
d[nx<<1+1]:=d[nx<<1+1] or t[2,nx]
end;
t[1,nx]:=maxk;t[2,nx]:=0
end;
procedure updata(x:longint);
begin
while x<>0 do begin
d[x]:=d[x<<1] xor d[x<<1+1];
x:=x>>1
end
end;
procedure change1(l,r,k:longint);
var ll,rr:longint;
begin
l:=l+m1-1;r:=r+m1+1;
ll:=l>>1;rr:=r>>1;
pushdown(l);pushdown(r);
while not (l xor r=1) do begin
if l and 1=0 then begin d[l+1]:=d[l+1] and k;t[2,l+1]:=t[2,l+1] and k;t[1,l+1]:=t[1,l+1] and k end;
if r and 1=1 then begin d[r-1]:=d[r-1] and k;t[2,r-1]:=t[2,r-1] and k;t[1,r-1]:=t[1,r-1] and k end;
l:=l>>1;r:=r>>1
end;
updata(ll);updata(rr)
end;
procedure change2(l,r,k:longint);
var ll,rr:longint;
begin
l:=l+m1-1;r:=r+m1+1;
ll:=l>>1;rr:=r>>1;
pushdown(l);pushdown(r);
if l and 1=0 then d[l+1]:=d[l+1] or k;l:=l>>1;
if r and 1=1 then d[r-1]:=d[r-1] or k;r:=r>>1;
// k:=k xor maxk;
while not (l xor r=1) do begin
if l and 1=0 then begin d[l+1]:=d[l+1] and (k xor maxk);t[2,l+1]:=t[2,l+1] or k end;
if r and 1=1 then begin d[r-1]:=d[r-1] and (k xor maxk);t[2,r-1]:=t[2,r-1] or k end;
l:=l>>1;r:=r>>1
end;
updata(ll);updata(rr)
end;
function ask(l,r:longint ): longint;
begin
l:=l+m1-1;r:=r+m1+1;
pushdown(l);pushdown(r);ask:=0;
while not(l xor r=1) do begin
if l and 1=0 then ask:=ask xor d[l+1];
if r and 1=1 then ask:=ask xor d[r-1];
l:=l>>1;r:=r>>1
end
end;
procedure init;
var x,ch,i,l,r,k:longint;
begin
readln(n,m);
origin;
for i:=1 to n do begin
read(x);
d[(i+m1)]:=x;
updata((i+m1)>>1)
end;
readln;
for i:=1 to m do begin
read(ch);
if ch=1 then begin
readln(l,r,k);
change1(l,r,k)
end
else if ch=2 then begin
readln(l,r,k);
change2(l,r,k)
end
else begin
readln(l,r);
ans:=ask(l,r);
writeln(ans)
end
end;
end;
begin
inf;
init;
ouf
end.