Solution - P1896 [SCOI2005] 互不侵犯
其实就是炮兵阵地的改版,但是改得不多。
思路
预处理每一行的合法状况,然后跑一遍状压 DP 就行了。注意放置国王的位置有限制。
另外警示后人:
- 十年 OI 一场空,不开________见祖宗;
- 枚举已经放置的国王数量的时候从 \(0\) 开始。
然后,没了。
代码
#include <bits/stdc++.h>
#define rint register int
#define rllong register long long
#define llong long long
#define N 10
using namespace std;
llong dp[N][N*N][1<<N], ans;
int sit[1<<N], val[1<<N], cnt;
int n, m;
inline int popcnt(rint x){
rint cnt = 0;
while(x){
if(x & 1) ++cnt;
x >>= 1;
}
return cnt;
}
int main(){
scanf("%d %d", &n, &m);
for(rint i = 0; i < (1<<n); ++i)
if(!(i&(i<<1)))
++cnt, sit[cnt] = i, val[cnt] = popcnt(i);
for(rint i = 1; i <= cnt; ++i)
dp[1][val[i]][sit[i]] = 1;
for(rint i = 2; i <= n; ++i){
for(rint j = 0; j <= m; ++j){
for(rint k = 1; k <= cnt; ++k){
rint now = sit[k], val1 = val[k];
if(j < val1) continue;
for(rint l = 1; l <= cnt; ++l){
rint lst = sit[l], val2 = val[l];
if(now<<1&lst || now>>1&lst || now&lst) continue;
dp[i][j][now] += dp[i-1][j-val1][lst];
}
}
}
}
for(rint i = 1; i <= cnt; ++i)
ans += dp[n][m][sit[i]];
printf("%lld", ans);
return 0;
}

浙公网安备 33010602011771号