zoukankan      html  css  js  c++  java
  • [BZOJ1087][SCOI2005]互不侵犯King解题报告|状压DP

    在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

      好像若干月前非常Naive地去写过DFS...

      然后其实作为状压DP是一道非常好的题啦><

      感觉直接无脑搞时间是下不来的 做了好几道预处理

      使得最后DP的过程中没有任何一条转移是无用的

      

     1 program bzoj1087;
     2 var i,x,n,k,j,p,q,t1,t2:longint;
     3     ans:int64;
     4     a:array[-1..512]of longint;
     5     b:array[-1..9,-1..100]of longint;
     6     c:array[-1..512,-1..512]of longint;
     7     f:array[0..1,-1..512,-1..512]of int64;
     8 
     9 function check(x:longint):boolean;
    10 var las:longint;
    11 begin
    12     las:=0;
    13     while x<>0 do
    14     begin
    15         if (x and 1=1)and(las=1) then exit(false);
    16         las:=x and 1;
    17         x:=x >> 1;
    18     end;
    19     exit(true);
    20 end;
    21 
    22 function count(x:longint):longint;
    23 var tem:longint;
    24 begin
    25     tem:=0;
    26     while x<>0 do
    27     begin
    28         inc(tem,x and 1);
    29         x:=x >> 1;
    30     end;
    31     exit(tem);
    32 end;
    33 
    34 function ok(x,y:longint):boolean;
    35 var i:longint;
    36     tmp:array[0..1,-1..10]of longint;
    37 begin
    38     for i:=8 downto 0 do tmp[0,i]:=x >> i and 1;
    39     for i:=8 downto 0 do tmp[1,i]:=y >> i and 1;
    40     for i:=0 to 8 do if (tmp[0,i]+tmp[1,i]=2)or(tmp[0,i]+tmp[1,i-1]=2)or(tmp[0,i]+tmp[1,i+1]=2) then exit(false);
    41     exit(true);
    42 end;
    43 
    44 begin
    45     fillchar(b,sizeof(b),0);
    46     fillchar(a,sizeof(a),0);
    47     fillchar(c,sizeof(c),0);
    48         readln(n,k);
    49         for i:=0 to 1 << n-1 do if check(i) then
    50     begin
    51             x:=count(i);
    52         inc(b[x,0]);b[x,b[x,0]]:=i;
    53         inc(a[0]);a[a[0]]:=i;
    54     end;
    55     for i:=1 to a[0] do
    56         for j:=1 to a[0] do if ok(a[i],a[j]) then begin inc(c[a[i],0]);c[a[i],c[a[i],0]]:=a[j];end;
    57     fillchar(f,sizeof(f),0);
    58     for i:=0 to k do
    59         for j:=1 to b[i,0] do f[1,i,b[i,j]]:=1;
    60     for i:=2 to n do
    61     begin
    62         f[0]:=f[1];
    63         fillchar(f[1],sizeof(f[1]),0);
    64         for j:=0 to k do
    65             for p:=0 to (n+1) >> 1 do if p<=j then
    66             begin
    67                 q:=j-p;
    68                 for t1:=1 to b[p,0] do
    69                     for t2:=1 to c[b[p,t1],0] do inc(f[1,j,b[p,t1]],f[0,q,c[b[p,t1],t2]]);
    70             end;
    71     end;
    72     ans:=0;
    73     for i:=1 to a[0] do inc(ans,f[1,k,a[i]]);
    74     writeln(ans);
    75 end.
  • 相关阅读:
    LOJ 6089 小Y的背包计数问题 —— 前缀和优化DP
    洛谷 P1969 积木大赛 —— 水题
    洛谷 P1965 转圈游戏 —— 快速幂
    洛谷 P1970 花匠 —— DP
    洛谷 P1966 火柴排队 —— 思路
    51Nod 1450 闯关游戏 —— 期望DP
    洛谷 P2312 & bzoj 3751 解方程 —— 取模
    洛谷 P1351 联合权值 —— 树形DP
    NOIP2007 树网的核
    平面最近点对(加强版)
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4480049.html
Copyright © 2011-2022 走看看