题目描述
这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!
输入输出格式
输入格式:
一行包含两个整数N,M,之间由一个空格隔开。
输出格式:
总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。
输入输出样例
输入样例#1:
1 3
输出样例#1:
7
说明
样例说明
除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。
数据范围
100%的数据中N和M均不超过100
50%的数据中N和M至少有一个数不超过8
30%的数据中N和M均不超过6
动态规划(组合数+状压,选择合理的状态)
见代码(感谢 @何旭):
#include<cstdio> using namespace std; #define mod f[i][j][k]%=9999973 int n,m; ][][]; long long calc(int x) { )>>; } /* 发个题解,但是我并不打算发程序,下面的程序够详细了,我只是补个思想讲解 F[I][J][K] 表示已经放了前I行,其中有J列是只放了1个炮,有K列放了2个炮的方案数 有:(已第三方订正) 1〉如果第I行不放,有 F[i][J][K]+=+F[I-1][J][K]; 2〉如果第I行放一个棋子,且这个棋子放在已经放了一个棋子的列上,有 F[I][J][K]+=F[I-1][J+1][K-1]*(J+1); 3〉如果第I行放一个棋子,且这个棋子放在已放了0个棋子的列上,有: F[I][J][K]+=F[I-1][J-1][K]*(M-J-K+1); 4〉如果第I列放两个棋子,且两个棋子都放在空列上,有: F[I][J][K]+=F[i-1][J-2][K]*(M-J+2-K)*(M-J+1-K) DIV 2; 5〉如果第I列放两个棋子,且两个棋子一个放在已经放了一个棋子的列,另一个放在放了0个棋子的列。有 F[I][J][K]+=F[I-1][J+2][K-2]*(J+2)*(J+1)DIV 2 ; 6〉如果第I列放两个棋子,且这两个棋子都放在已经放过1个棋子的列上,有: F[I][J][K]+=F[I-1][J][K-1]*J*(M-J-K+1); 7〉 F[I][J][K] 的每次累计必须mod 9999973; */ int main() { scanf("%d%d",&n,&m); f[][][]=; ; i<=n; i++) { ; j<=m; j++) ; k<=m-j; k++) { f[i][j][k]=f[i-][j][k]; ) f[i][j][k]+=f[i-][j-][k]*(m-j-k+),mod; ) f[i][j][k]+=f[i-][j+][k-]*(j+),mod; ) f[i][j][k]+=f[i-][j-][k]*calc(m-j+-k),mod; ) f[i][j][k]+=f[i-][j+][k-]*calc(j+),mod; ) f[i][j][k]+=f[i-][j][k-]*j*(m-j-k+),mod; } } ; ; i<=m; i++) { ; j<=m; j++) ans+=f[n][i][j],ans%=; } printf("%lld\n",ans); }