https://www.luogu.org/problemnew/show/P1896
dp[i][j][l] 三維狀態
i表示第幾行 j表示狀態,l表示所用國王數
題中給了n最大爲9 那麼狀態數就是1<<9
我們先預處理所需的數據,即某一狀態是否合法,及當前狀態所需的國王數
上下行需要滿足 (h&j) == 0 && ((h<<1)&j) == 0 && ((h>>1)&j) == 0 即 國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各一個格子
然後疊加就可以了 記得開longlong 否則數據會爆int
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 100;
const int M = 1e7 + 100;
const int INF = 0x3f3f3f3f;
const int mod = 100000000;
ll n,k,dp[20][(1<<10)+100][110],need[(1<<10)+100],vis[(1<<10)+100];
int main()
{
cin >> n >> k;
//預處理每種狀態所需的國王數
for(int i = 0;i < (1<<n);i ++){
int t = i;
while(t){
if(t&1) need[i] ++;
t >>= 1;
}
}
//預處理合適的狀態
for(int i = 0;i < (1<<n);i ++) if(((i<<1)&i) == 0) vis[i] = 1;
//預處理第一行
for(int i = 0;i < (1<<n);i ++) if(vis[i] && need[i] <= k) dp[1][i][need[i]] = 1;
for(int i = 2;i <= n;i ++){
for(int j = 0;j < (1<<n);j ++){
if(vis[j]){
for(int h = 0;h < (1<<n);h ++){
if(vis[h] && (h&j) == 0 && ((h<<1)&j) == 0 && ((h>>1)&j) == 0){
for(int len = k;len >= need[j];len --)
dp[i][j][len] += dp[i-1][h][len-need[j]];
}
}
}
}
}
ll ans = 0;
for(int i = 0;i < (1<<n);i ++) ans += dp[n][i][k];
cout << ans;
return 0;
}