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;
}

posted @ 2025-04-20 17:14  Hootime  阅读(33)  评论(0)    收藏  举报