日常训练20161013 棋盘上的象

来源:互联网 发布:untitled软件汉化版 编辑:程序博客网 时间:2024/05/01 01:47

题意:求将k个象摆在nn的棋盘上,保证他们互相不能攻击的方案数。(n8,0kn2)

一开始想用类似8皇后的位运算来做,但皇后每行只能放一个,象每行可以放多个,同样的方法枚举复杂度就会高很多。复杂度无法估计,每层转移2n但不满,反正这种复杂度只过了70%的点。

var  n,k,limit:longint;  ans:int64;function count(x:longint):longint;  begin    count:=0;    while x>0 do      begin        inc(count,x and 1);        x:=x>>1;      end;  end;procedure dfs(dep,left,right,sum:longint);  var    can,now:longint;  begin    if (dep>n) then      begin        inc(ans,ord(sum=k));        exit;      end;    can:=(limit xor (left or right));    now:=can;    while now>0 do      begin        if sum+count(now)<=k          then dfs(dep+1,((left or now)<<1) and limit,(right or now)>>1,sum+count(now));        now:=(now - 1) and can;      end;    if sum+count(now)<=k      then dfs(dep+1,(left<<1) and limit,right>>1,sum+count(now));  end;begin  assign(input,'elephant.in');reset(input);  assign(output,'elephant.out');rewrite(output);  read(n,k);  limit:=1<<n-1;  dfs(1,0,0,0);  writeln(ans);  close(input);close(output);end.

实际上如果把棋盘斜过来,黑白染色,分成两块棋盘,每块棋盘上的象其实就相当于車了,而且上下行可以互换,那样把两个棋盘的行都按照从小到大排列,那么一个棋盘的每行格子数就是1 1 3 3 5 5......另一个棋盘每行格子数为2 2 4 4,这样就可以n2dp,用f[i][j]表示前i行取了j个有多少种方案,最后统计答案只要枚举一下每个棋盘上放了多少个棋子即可。

const  MAXN=8;var  f,g:array[0..MAXN*2,0..MAXN*2] of int64;  a,b:array[0..MAXN*2] of int64;  n,k,i,j:longint;  ans:int64;procedure print(x:int64);  begin    writeln(x);    close(input);close(output);    halt;  end;function max(a,b:longint):longint;  begin if (a>b) then exit(a) else exit(b); end;function min(a,b:longint):longint;  begin if (a<b) then exit(a) else exit(b); end;begin  assign(input,'elephant.in');reset(input);  assign(output,'elephant.out');rewrite(output);  read(n,k);  if (n=1) then print(1);  if (k>(n-1)<<1) then print(0);  for i:=1 to n do    if (i and 1=1)      then a[i]:=i      else a[i]:=a[i-1];  for i:=1 to n-1 do    if (i and 1=1)      then b[i]:=i+1      else b[i]:=b[i-1];  f[0][0]:=1;  for i:=0 to n-1 do    for j:=0 to a[i] do      begin        inc(f[i+1][j],f[i][j]);        inc(f[i+1][j+1],f[i][j] * (a[i+1] - j));      end;  g[0][0]:=1;  for i:=0 to n-2 do    for j:=0 to b[i] do      begin        inc(g[i+1][j],g[i][j]);        inc(g[i+1][j+1],g[i][j] * (b[i+1] - j));      end;  for i:=max(0,k-b[n-1]) to min(a[n],k) do    inc(ans,f[n][i] * g[n-1][k-i]);  print(ans);  close(input);close(output);end.
0 0