You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.
# include <bits/stdc++.h>
using namespace std ;
typedef long long LL ;
const int N = 11 ; //棋盘的长宽上限
const int M = 1 < < 10 ; //二进制枚举的状态数量上限, 因为n最大是10,就是2^10个状态
const int K = 110 ; //国王的个数上限
int n ; //n*n的棋盘
int m ; //国王的数量
vector < int > st ; //所有合法的状态(预处理的结果)
vector < int > head [ M ] ; //某个状态兼容哪些状态(预处理的结果)
int cnt [ M ] ; //记录每种状态中的数字1个数, 了解本行使用了多少个国王
//完成前i行, 使用了j个国王, 现在的状态是k:001010111之类, 存在的是二进制对应的十进制数
LL f [ N ] [ K ] [ M ] ;
//判断一行是不是有连续1
bool check ( int x ) {
return ! ( x & x > > 1 ) ;
}
//统计某个状态中数字1的数量
int count ( int x ) {
int res = 0 ;
for ( int i = 0 ; i < 32 ; i + + ) res + = x > > i & 1 ;
return res ;
}
int main ( ) {
cin > > n > > m ;
//1、可行的合法状态预处理
for ( int i = 0 ; i < 1 < < n ; i + + )
if ( check ( i ) ) st . push_back ( i ) , cnt [ i ] = count ( i ) ;
//i与i-1行之间的兼容关系记录下来
for ( int a : st )
for ( int b : st )
//a&b==0:同列不是同时为1, 表示列上面国王不冲突
//check(a|b): 经或处理后的数字, 如果存在连续的1, 就表示斜45度有国王, 不合法,妙不可言
if ( ( a & b ) = = 0 & & check ( a | b ) ) head [ a ] . push_back ( b ) ; //记录合法的状态转移关系
//2、DP
//已经摆完了前0行, 放置了0个国王, 当前状态全是0, 这种情况下只有全是0的状态是合法的, 方案数为0.
f [ 0 ] [ 0 ] [ 0 ] = 1 ;
for ( int i = 1 ; i < = n ; i + + ) //枚举每一行
for ( int j = 0 ; j < = m ; j + + ) //枚举国王个数
for ( int a : st ) { //枚举第i行的每一种可能状态
for ( int b : head [ a ] ) { //s状态与哪些状态兼容
int c = cnt [ a ] ; //状态st[s]的国王数量也可以一并预处理出来,当然也可以现用现算
//上面的j循环, 限定了国王的数量上限
if ( j > = c ) f [ i ] [ j ] [ a ] + = f [ i - 1 ] [ j - c ] [ b ] ; //从上一层的状态转化而来
}
}
//结果
LL ans = 0 ;
//在填充完n行之后, 将m个国王放完, 每一个合法状态都是可能的解, 需要累加起来才是答案
for ( int a : st ) ans + = f [ n ] [ m ] [ a ] ;
printf ( " %lld " , ans ) ;
return 0 ;
}