「Nescafé 29」杯HE两校联赛(第二轮Day2)

      这次比赛没有AK的,120分的有57人,我110分,zzm神犇第一题比我多被坑一个点,但是人家第二题想到正解。

A 穿越七色虹

      二分以后判定是个线段覆盖。忘记去掉在x0右边的区间WA第一个和第三个点,改了以后WA5个点,不想调了。

program rainbow;
uses math;
const FileName='rainbow';
var x,r,a,b:array[0..10] of extended;
    temp,ra,rb,la,lb,left,right,mid,x0,h:extended;
    i,time:longint;
procedure swap(var x,y:extended);
          var t:extended;
          begin t:=x;x:=y;y:=t;end;
function  cmp(i,j:longint):boolean;
          begin
          if a[i]<a[j] then exit(true);
          if a[i]>a[j] then exit(false);
          if b[i]<b[j] then exit(true);
          if b[i]>b[j] then exit(false);
          exit(true);
          end;
function  check(n:extended):boolean;
          var tot,i,j:longint;
              range,nr,delta:extended;
          begin tot:=0;
          for i:=1 to 7 do
            if r[i]+n>h then
              begin
              nr:=r[i]+n;
              delta:=sqrt(nr*nr-h*h);
              inc(tot);
              a[tot]:=x[i]-delta;
              b[tot]:=x[i]+delta;
              if a[tot]>x0 then dec(tot);
              end;
          if tot=0 then exit(false);
          //sort
          for i:=1 to 6 do
            for j:=i to 7 do
              if not cmp(i,j)
                then begin
                swap(a[i],a[j]);
                swap(b[i],b[j]);
                end;
          //work
          if a[1]>0 then exit(false);
          range:=b[1];
          for i:=2 to tot do
            if a[i]<range
              then range:=max(b[i],range)
              else exit(false);
          if range>x0 then exit(true)
                      else exit(false);
          end;
begin
readln(h,x0);right:=31623;left:=0;time:=0;
for i:=1 to 7 do begin
  readln(x[i],r[i]);
  la:=x[i];lb:=x0-x[i];
  ra:=sqrt(la*la+h*h+10);rb:=sqrt(lb*lb+h*h+10);
  if(ra>r[i])or(rb>r[i])
    then begin
         temp:=-1E6;
         if ra*ra-la*la>=h*h then temp:=max(temp,ra-r[i]);
         if rb*rb-lb*lb>=h*h then temp:=max(temp,rb-r[i]);
         if temp>0 then right:=min(right,temp);
         end;
  end;
right:=right+h;
if check(0)
  then writeln('0.00')
  else begin
       while(abs(right-left)>1E-6)and
            (time<=10000)do
         begin
         inc(time);
         mid:=(left+right)/2;
         if check(mid)
           then right:=mid
           else left:=mid;
         end;
       writeln(right:2:2);
       end;
end.

 

B 四叶草魔杖

      看数据范围蒙了个状压DP求最优哈密顿路,骗到30分。据说直接MST能80?

program clover;
uses math;
const FileName='clover';
      inf=maxlongint div 2;
var   u,v,bitset,ans,n,m,fall,i,p,q,t,tot:longint;
      f:array[0..16,0..$FFFF] of longint;
      w:array[0..16,0..16] of longint;
      a:array[0..16] of longint;
begin
readln(n,m);fall:=1<<n-1;ans:=inf;
filldword(w,sizeof(w) shr 2, -1);
filldword(f,sizeof(f) shr 2,inf);
for i:=1 to n do read(A[i]);
for i:=1 to m do
   begin
   readln(p,q,t);
   w[p][q]:=t;
   w[q][p]:=t;
   end;
for i:=0 to n-1 do f[i][1<<i]:=0;
for bitset:=0 to fall do
   for u:=0 to n-1 do if((bitset shr u)and 1)=1 then
     for v:=0 to n-1 do if(((bitset shr v)and 1)=1)and(w[v][u]<>-1)
       then f[u][bitset]:=min(f[v][bitset xor 1<<u]+w[v][u],f[u][bitset]);
for i:=0 to n-1 do
   ans:=min(f[i][fall],ans);
if ans<>inf
  then writeln(ans)
  else writeln('Impossible');
end.

 

      等会学一下正解。orz zzm神犇。由于MST搞完cnt不会比N大,所以秒过。应该意识到这是一个MST删边的问题。首先一个MST是可以满足能量的要求的。然后答案应该是几个子图的MST,每个子图sigma(a[i])=0,然后枚举边的所有组合,BFS验证即可。

#01: Accepted (0ms, 700KB)
#02: Accepted (0ms, 700KB)
#03: Accepted (0ms, 700KB)
#04: Accepted (0ms, 700KB)
#05: Accepted (0ms, 700KB)
#06: Accepted (0ms, 700KB)
#07: Accepted (0ms, 700KB)
#08: Accepted (0ms, 700KB)
#09: Accepted (0ms, 700KB)
#10: Accepted (0ms, 700KB)
Accepted / 100 / 0ms / 700KB

program clover;
uses math;
const FileName='clover';
      inf=maxlongint div 2;
var   temp,cnt,bitset,ans,n,m,fall,i,j,vi,ui,t,tot:longint;
      Q,father:array[0..16] of longint;
      map:array[0..16,0..16] of longint;
      a:array[0..16] of longint;
      u,v,w,new:array[0..120] of longint;
      vis:array[0..16] of boolean;
procedure swap(var a,b:longint);
          var t:longint;begin t:=a;a:=b;b:=t;end;
function  find(x:longint):longint;
          var t:longint;
          begin
          if father[x]=x then exit(x);
          t:=find(father[x]);
          father[x]:=t;
          exit(t);
          end;
procedure union(x,y:longint);
          begin father[find(x)]:=find(y);end;
function  check(bitset:longint;var sum:longint):boolean;
          var cur,h,t,i,j,temp:longint;
          begin sum:=0;
          fillchar(vis,sizeof(vis),false);
          for i:=0 to cnt do
            if(((bitset>>i)and 1)=1)
              then inc(sum,w[new[i]]);
          for i:=0 to n-1 do
            if not vis[i]
              then begin
                   h:=0;t:=1;Q[1]:=i;
                   vis[i]:=true;temp:=a[i];
                   while h<t do begin
                     inc(h);cur:=Q[h];
                     for j:=0 to n-1 do
                     if(not vis[j])and(map[cur][j]<>-1)and
                       (((bitset shr map[cur][j])and 1)=1)
                       then begin
                            inc(t);Q[t]:=j;
                            vis[j]:=true;
                            inc(temp,a[j]);
                            end;
                     end;
                   if temp<>0 then exit(false);
                   end;
          exit(true);
          end;
begin
readln(n,m);fall:=(1<<n)-1;
ans:=inf;cnt:=-1;
filldword(map,sizeof(map) shr 2, -1);
for i:=0 to n-1 do
  begin
  read(A[i]);
  father[i]:=i;
  end;
for i:=1 to m do
   begin
   readln(vi,ui,t);
   u[i-1]:=vi;
   v[i-1]:=ui;
   w[i-1]:=t;
   end;
for i:=0 to m-2 do
  for j:=i to m-1 do
    if w[j]<w[i]
      then begin
           swap(u[i],u[j]);
           swap(v[i],v[j]);
           swap(w[i],w[j]);
           end;
for i:=0 to m-1 do
  if find(v[i])<>find(u[i])
    then begin
         inc(cnt);new[cnt]:=i;
         map[v[i]][u[i]]:=cnt;
         map[u[i]][v[i]]:=cnt;
         union(v[i],u[i]);
         end;
if(cnt=-1)
  then begin
       if check(0,temp)
         then writeln(0)
         else writeln('Impossible');
       end
  else begin
       for i:=0 to (1<<(cnt+1))-1 do
         if check(i,temp)
           then ans:=min(ans,temp);
       if ans<>inf
         then writeln(ans)
         else writeln('Impossible');
       end;
end.

 

 

C 圣主的考验

      知道是DP而不会做的感觉,无力啊。

posted @ 2012-11-04 12:54  ljlin  阅读(369)  评论(0编辑  收藏  举报