1. 1. 题目
  2. 2. [SCOI2005] 互不侵犯
    1. 2.1. 题目描述
  3. 3. 题解
  4. 4. 问题
  5. 5. 代码

题目

[SCOI2005] 互不侵犯

题目描述

N×NN \times N 的棋盘里面放 KK 个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 88 个格子。
对于全部数据,1N91 \le N \le 90KN×N0 \le K \le N\times N

题解

f[i][j][k]表示推到了第i行,到目前为止选了j个国王,第i行的状态为k的方案数

然后枚举i,j,k以及前一行的状态转移即可

问题

1.不开long long见祖宗

2.第二位要开N * N

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include<bits/stdc++.h>
#define int long long
using namespace std;

int read()
{
int f = 1, x = 0;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}

while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return f * x;
}
const int N = 10;
int f[N][N * N][1 << 9];
int sum[1 << 9];
int n, k;

int getsum(int x)
{
int ans = 0;
while(x)
{
x &= (x - 1);
ans++;
}
return ans;
}

signed main()
{
for(int i = 0;i < (1 << 9);i++)
{
sum[i] = getsum(i);
}
n = read(), k = read();
for(int s = 0;s < (1 << n);s++)
{
f[1][sum[s]][s] = 1;
}

for(int i = 2;i <= n;i++)
{
for(int j = 0;j <= k;j++)
{
for(int s = 0;s < (1 << n);s++)
{
if((s >> 1) & s || (s << 1) & s || sum[s] > j) continue;
for(int fl = 0;fl < (1 << n);fl++)
{
if((fl >> 1) & fl || (fl << 1) & fl || (fl << 1) & s || fl & s || (fl >> 1) & s || sum[fl] + sum[s] > j) continue;
f[i][j][s] += f[i - 1][j - sum[s]][fl];
}
}
}

}

long long ans = 0;
for(int s = 0; s < (1 << n);s++)
{
if((s >> 1) & s) continue;
ans += f[n][k][s];
}
cout << ans;
return 0;
}