几道题目

48 篇文章 0 订阅
21 篇文章 0 订阅

第一题:在数列中选不同的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.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是牛客网数据分析方面的几道题目: 1. 某公司有一个销售平台,需要你通过数据分析找出哪些销售员的业绩最好。请根据以下表格结构,编写 SQL 查询语句,返回销售员的姓名、销售总额和销售数量,按销售总额从高到低排序。 | 销售员编号 | 销售员姓名 | 销售日期 | 销售金额 | |-----------|-----------|---------|---------| | 001 | 张三 | 2021-02-01 | 5000 | | 002 | 李四 | 2021-02-02 | 3000 | | 001 | 张三 | 2021-02-03 | 10000 | | 003 | 王五 | 2021-02-04 | 8000 | | 002 | 李四 | 2021-02-05 | 6000 | | 001 | 张三 | 2021-02-06 | 7000 | 2. 某公司有一个电商平台,需要你通过数据分析找出哪些商品的销售量最好。请根据以下表格结构,编写 SQL 查询语句,返回商品名称、销售总量和销售总额,按销售总量从高到低排序。 | 商品编号 | 商品名称 | 销售日期 | 销售数量 | 商品单价 | |-----------|-----------|---------|---------|---------| | 001 | 商品A | 2021-02-01 | 10 | 500 | | 002 | 商品B | 2021-02-02 | 15 | 300 | | 001 | 商品A | 2021-02-03 | 20 | 500 | | 003 | 商品C | 2021-02-04 | 25 | 200 | | 002 | 商品B | 2021-02-05 | 30 | 300 | | 001 | 商品A | 2021-02-06 | 35 | 500 | 3. 某电商平台有一个用户行为表,记录了用户在平台上的操作记录。请根据以下表格结构,编写 SQL 查询语句,返回每个用户在平台上的操作总数和最近一次操作的时间。 | 用户编号 | 操作类型 | 操作时间 | |-----------|-----------|---------| | 001 | 登录 | 2021-02-01 10:00:00 | | 002 | 注册 | 2021-02-02 10:00:00 | | 001 | 浏览商品 | 2021-02-02 11:00:00 | | 002 | 下单 | 2021-02-03 10:00:00 | | 001 | 支付订单 | 2021-02-03 11:00:00 | | 003 | 注册 | 2021-02-04 10:00:00 | | 001 | 评价商品 | 2021-02-04 11:00:00 | | 002 | 浏览商品 | 2021-02-05 10:00:00 | | 003 | 下单 | 2021-02-06 10:00:00 | | 001 | 登出 | 2021-02-06 11:00:00 | 以上是三道数据分析方面的牛客网题目,希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值