Codeforces #377 (Div.2) E. Sockets

9 篇文章 0 订阅
2 篇文章 0 订阅

原题网址:http://codeforces.com/contest/732/problem/E

这里写图片描述
这里写图片描述
从小到大枚举每个插座,将插座不断/2在hash表中找是否有与之匹配的(贪心思想)。这里hash表里相同元素还有不同标号,我将这些标号再拉一次链,复杂度上就有保证了(一开始相同元素直接丢一块没拉链就T了)。(拉链套拉链WA了好几发。。)

type
  rec=record
        v,i,next,first:longint;
      end;
  rec2=record
         i,next:longint;
       end;
const
  MX=200050;
  p=199999;
var
  map:array[0..MX] of rec;
  mp:array[0..MX] of rec2;
  socket,num,used,match,real_used,first:array[0..MX] of longint;
  n,m,i,f,now_used,tot_match,s,ss,t:longint;
  tot_used:int64;
procedure swap(var a,b:longint);
  var t:longint;
  begin t:=a;a:=b;b:=t;end;
procedure sort(l,r:longint);
  var
    i,j,e:longint;
  begin
    i:=l;j:=r;e:=socket[(l+r)>>1];
    repeat
      while socket[i]<e do inc(i);
      while e<socket[j] do dec(j);
      if not (i>j) then
        begin
          swap(socket[i],socket[j]);
          swap(num[i],num[j]);
          inc(i);dec(j);
        end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r);
  end;
procedure push(x,i:longint);
  var
    lab,t:longint;
  begin
    lab:=x mod p;
    t:=first[lab];
    while (t>0) do
      begin
        if (map[t].v=x) then
          begin
            inc(ss);mp[ss].i:=i;
            mp[ss].next:=map[t].first;
            map[t].first:=ss;
            exit;
          end;
        t:=map[t].next;
      end;
    inc(s);map[s].v:=x;
    map[s].next:=first[lab];first[lab]:=s;
    inc(ss);mp[ss].i:=i;
    mp[ss].next:=map[s].first;
    map[s].first:=ss;
  end;
function find(x:longint):longint;
  var
    lab,t,tt:longint;
  begin
    lab:=x mod p;
    t:=first[lab];
    while (t>0) do
      begin
        if (map[t].v=x) then
          begin
            tt:=map[t].first;
            if (tt=0) then exit(-1);
            map[t].first:=mp[tt].next;
            exit(mp[tt].i);
          end;
        t:=map[t].next;
      end;
    exit(-1);
  end;
begin
  //assign(input,'E.in');reset(input);
  //assign(output,'E.out');rewrite(output);
  read(n,m);
  for i:=1 to n do
    begin
      read(t);
      push(t,i);
    end;
  for i:=1 to m do read(socket[i]);
  for i:=1 to m do num[i]:=i;
  sort(1,m);
  for i:=1 to m do
    begin
      now_used:=0;used[i]:=-1;
      while (used[i]=-1)and(socket[i]>1) do
        begin
          f:=find(socket[i]);
          if (f<>-1) then
            begin
              used[i]:=now_used;
              match[f]:=num[i];
              inc(tot_match);
              inc(tot_used,now_used);
            end;
          socket[i]:=socket[i]>>1+socket[i] and 1;
          inc(now_used);
        end;
      if (used[i]<>-1) then continue;
      f:=find(socket[i]);
      if (f<>-1)
        then
          begin
            used[i]:=now_used;
            match[f]:=num[i];
            inc(tot_match);
            inc(tot_used,now_used);
          end
        else used[i]:=0;
    end;
  for i:=1 to m do real_used[num[i]]:=used[i];
  writeln(tot_match,' ',tot_used);
  for i:=1 to m-1 do
    write(real_used[i],' ');
  writeln(real_used[m]);
  for i:=1 to n-1 do
    write(match[i],' ');
  writeln(match[n]);
  //close(input);close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值