首页 > 代码库 > BZOJ1298骰子的学问

BZOJ1298骰子的学问

技术分享

技术分享

 

题解:

把ai认为是i的父亲,使其连边,那么题目给出的关系构成了一个基环树森林。

对于在环外、指向环的边(即“树”的部分),使骰子的每一个面都比其父亲大。

观察1、4样例可以发现一个构造方式:对于一个大小为n环,从第一个点开始,逆着父亲边放入1~n;再从第一个点在环上的儿子开始,逆着父亲边以此放入n+1~2*n,知道放满n*m个数。

但是这个构造法在样例3中失败了。事实上,可以证明,只有在像样例3这种环大小为3,骰子面数为4的情况下,该方法会失效。对于这种情况,进行特判。

注意环大小为2或是m<=2的情况,一定无法构造。

 

代码:

const
  bb:array[1..12]of longint=(1,2,4,3,7,5,10,8,6,11,9,12);
var
  i,j,k,l,n,m,cnt:longint;
  fa,a,b,c:array[0..1001]of longint;
  d:array[0..1001,0..1001]of longint;
procedure ss2(x:longint);
var i:longint;
begin
  if a[x]<2 then
  begin
    for i:=1 to m do
    begin inc(cnt); d[x,i]:=cnt; end;
    a[x]:=2;
  end;
  i:=c[x];
  while i>0 do
  begin
    if a[i]<2 then ss2(i);
    i:=b[i];
  end;
end;
procedure ss(x:longint);
var i,j,k,l,xx:longint;
begin
  a[x]:=1; x:=fa[x];
  while a[x]=0 do
  begin
    a[x]:=1; x:=fa[x];
  end;
  k:=1; xx:=fa[x]; a[x]:=2;
  while x<>xx do begin inc(k); a[xx]:=2; xx:=fa[xx]; end;
  if k<=2 then begin writeln(0); halt; end;
  if(k=3)and(m=4)then
  begin
    for i:=1 to 12 do
    begin
      d[x,1+((i-1)div 3)]:=bb[i];
      x:=fa[x];
    end;
  end else
  begin
    for i:=1 to m do
    begin
      l:=cnt+k;
      for j:=1 to k do
      begin
        d[x,i]:=l; dec(l);
        if j<>k then x:=fa[x];
      end;
      cnt:=cnt+k;
    end;
  end;
  for i:=1 to k do
  begin
    ss2(x); x:=fa[x];
  end;
end;
begin
  readln(n,m);
  for i:=1 to n do
  begin
    read(fa[i]);
    b[i]:=c[fa[i]]; c[fa[i]]:=i;
  end;
  for i:=1 to n do
  if a[i]=0 then ss(i);
  for i:=1 to n do
  begin
    for j:=1 to m do write(d[i,j], );
    writeln;
  end;
end.

BZOJ1298骰子的学问