[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[i][j][k]表示前i行  有j列放了1个 棋子,有k列放了2个棋子  那么有(列数m - j - k)列放了0个棋子

然后考虑转移

dp[i][j][k]的转移要考虑当前列放几枚棋子
1:
当前列不放棋子   这时候的方案数和上一列一样
2:当前列放1个棋子   那么就要讨论放到了的那一列原本有几枚棋子
假设那一列没有,则dp[i][j][k]从dp[i - 1][j - 1][k] 转移而来,同时又(m - (j - 1) - k)种方法,乘法原理
假设那一列有一个,则 dp[i][j][k]从dp[i - 1][j + 1][k - 1] 转移而来同时有j + 1种方法乘法原理
3.当前列放两个棋子  那么要讨论放法
假设放到了两个空行  那么从dp[i - 1][j - 2][ k]转移而来,同时又C(m - ( j - 2) - k,2 )种方法 乘法原理
假设放到了两个有一个棋子的行  那么从 dp[i - 1][j + 2][ k - 2]转移而来,同时有C(j + 2,2)种方法 乘法原理
假设一个放到了空行,一个放到了有一个棋子的行  那么从dp[i - 1][j][k - 1]转移而来  同时有j * (k - 1)种方法乘法原理 

最后统计所有可能的解,相加输出即可 
*/


#include<cstdio>
#include<algorithm>
#include<iostream>
#define MOD 9999973
using namespace std;

int n,m;
long long  dp[131][131][131];

int c(int x)
{
    return (x * x - x) / 2;
}

int main()
{
    scanf("%d%d",&n,&m);
    dp[0][0][0] = 1;// 这个赋初值真的不明白 
    for(int i = 1;i <= n;i++)
    {
        for(int j = 0;j <= m;j++)
            for(int k = 0;j + k <= m;k++)
            {
                /*按照上面说的来*/
                dp[i][j][k] = dp[i - 1][j][k];
                if(k > 0)dp[i][j][k] += dp[i - 1][j + 1][k - 1] * (j + 1);
                if(j > 0)dp[i][j][k] += dp[i - 1][j - 1][k] * (m- j - k + 1);
                if(j > 1)dp[i][j][k] += dp[i - 1][j - 2][k] * c(m - j - k + 2);
                if(k > 1)dp[i][j][k] += dp[i - 1][j + 2][k - 2] * c(j + 2); 
                if(k > 0 && j > 0)dp[i][j][k] += dp[i - 1][j][k - 1] * j * (m - j - k + 1);
                dp[i][j][k] %= MOD;
            }    
    }
    long long ans = 0;
    for(int i = 0;i <= m;i++)
        for(int j = 0;j + i <= m;j++)
            ans = (ans + dp[n][i][j]) % MOD;
    cout << ans;
    return 0;
}
原文地址:https://www.cnblogs.com/luoyibujue/p/7663481.html