题目
[SCOI2005] 互不侵犯
题目描述
在 N×N 的棋盘里面放 K 个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 8 个格子。
对于全部数据,1≤N≤9,0≤K≤N×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; }
|