中国象棋[AHOI2009]

题目描述

这次小可可想解决的难题和中国象棋有关,在一个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

 题解:

  前30%明显是暴力

  50%是状压,不过是3进制下的,不太好写...

  一个明显的结论是不同的列(行)之间任意交换对答案是没有影响的。所以我们可以不用记录棋子防止的具体信息。我们设f[i][j][k]表示前i列有j列放了一个棋子、k列放了两个棋子的方案数。

  那么再考虑这个状态能由哪些状态转移过来。

  首先是第i列一个棋子也不放,那么f[i][j][k] = f[i-1][j][k]

  其次是放一个,这时有两种情况;最后是放两个,有三种情况。请读者自己思考=-=

 1 // f[i][j][k]表示前i行中有j列放了1个炮,k列放了两个炮的种类数 
 2 // f[i][j][k] = f[i-1][j][k] (一个都不放 
 3 //            + f[i-1][j-1][k]*(m-j-k+1) + f[i-1][j+1][k-1]*(j+1)  (放1个 
 4 //              + f[i-1][j-2][k]*C(m-j-k+2,2) + f[i-1][j][k-1]*j*(m-j-k+1) + f[i-1][j+2][k-2]*C(j+2,2) (放2个 
 5 #include<iostream>
 6 #include<cstdio>
 7 #include<cstring>
 8 #define LL long long
 9 #define RI register int
10 #define KI 9999973
11 using namespace std;
12 const int INF = 0x7ffffff ;
13 const int N = 100 + 10 ;
14 
15 inline int read() {
16     int k = 0 , f = 1 ; char c = getchar() ;
17     for( ; !isdigit(c) ; c = getchar())
18       if(c == '-') f = -1 ;
19     for( ; isdigit(c) ; c = getchar())
20       k = k*10 + c-'0' ;
21     return k*f ;
22 }
23 int n, m ; LL f[N][N][N] ;
24 
25 inline LL C(int x,int y) { return (x*(x-1)>>1)%KI ; }   // y都是2 
26 int main() {
27     n = read(), m = read() ;
28     f[1][0][0] = 1 ; f[1][1][0] = m ; f[1][2][0] = C(m,2) ;
29     for(int i=2;i<=n;i++) {
30         for(int j=0;j<=m;j++) {
31             for(int k=0;k<=m-j;k++) {
32                 f[i][j][k] = f[i-1][j][k] ;
33                 if(j) f[i][j][k] += f[i-1][j-1][k]*(m-j-k+1), f[i][j][k] %= KI ;
34                 if(k && j < m) f[i][j][k] += f[i-1][j+1][k-1]*(j+1), f[i][j][k] %= KI ;
35                 if(j > 1) f[i][j][k] += f[i-1][j-2][k]*C(m-j-k+2,2), f[i][j][k] %= KI ;
36                 if(k) f[i][j][k] += f[i-1][j][k-1]*j*(m-j-k+1), f[i][j][k] %= KI ;
37                 if(k > 1 && j < m-1) f[i][j][k] += f[i-1][j+2][k-2]*C(j+2,2), f[i][j][k] %= KI ;
38             }
39         }
40     }
41     int ans = 0 ;
42     for(int j=0;j<=m;j++) {
43         for(int k=0;k<=m-j;k++) ans += f[n][j][k], ans %= KI ;
44     }
45     printf("%d",ans) ;
46     return 0 ;
47 }

 

原文地址:https://www.cnblogs.com/zub23333/p/8717378.html