[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

 

 



 

然后我想到了压位dp,按3进制表示当前棋盘的状态,即某一列没有棋子,或者有一个,两个棋子,能过50分

接着可以发现,棋子的顺序是无所谓的,并不需要准确知道当前棋盘的状态

于是有了100分做法:dp[i][j][k]表示放了前i行,有j列是有1个棋子,有k列有两个棋子、



 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cctype>
 5 #include<cstring>
 6 #define mod 9999973
 7 #define int long long
 8 #define R register
 9 using namespace std;
10 inline  void in(int &x)
11 {
12     int f=1;x=0;char s=getchar();
13     while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
14     while(isdigit(s)){x=x*10+s-'0';s=getchar();}
15     x*=f;
16 }
17 int n,m,ans;
18 int f[108][108][108];
19 inline int C(int x)
20 {
21     return ((x*(x-1))/2)%mod;
22 }
23 signed main()
24 {
25     in(n),in(m);
26     f[0][0][0]=1;
27     for(R int i=1;i<=n;i++)
28     {
29         for(R int j=0;j<=m;j++)
30         {
31             for(R int k=0;k<=m-j;k++)
32             {
33                 f[i][j][k]=f[i-1][j][k];
34                 if(k>=1)(f[i][j][k]+=f[i-1][j+1][k-1]*(j+1));
35                 if(j>=1)(f[i][j][k]+=f[i-1][j-1][k]*(m-j-k+1));
36                 if(k>=2)(f[i][j][k]+=f[i-1][j+2][k-2]*(((j+2)*(j+1))/2));
37                 if(k>=1)(f[i][j][k]+=f[i-1][j][k-1]*j*(m-j-k+1));
38                 if(j>=2)(f[i][j][k]+=f[i-1][j-2][k]*C(m-j-k+2));
39                 f[i][j][k]%=mod;
40             }
41         }
42     }
43     for(R int i=0;i<=m;i++)
44         for(R int j=0;j<=m;j++)
45             (ans+=f[n][i][j])%=mod;
46     printf("%lld",(ans+mod)%mod);
47 }

 

上一篇:推荐一个JAVA学习地图(学习路线)并且包含JAVA实战项目的网站


下一篇:108、如何使用 Secret? (Swarm15)