zoukankan      html  css  js  c++  java
  • 洛谷P2051 [AHOI2009]中国象棋

    题目

    运用数学知识递推。定义(DP[i][j][k])为前i行内选择j个列只有一个炮,k列只有两个炮的放置方案总数。

    因为如果有一列或者一行的炮大于等于三时,必会有一个炮会被攻击到,所以可以用一个和两个来区分,方便递推。这样可以使的列里面的炮不会大于等于三,然后考虑行,这一行内只能放两个或一个,所以可以考虑从这方面来推出递推公式。放的这一个或两个炮会改变列上的炮数,所以可以从上一行的炮的状态转移。

    有递推公式:

    dp[i][j][k] = (dp[i][j][k] + (j + 1) * dp[i - 1][j + 1][k - 1]) % mod;//j+1个列里任选一个即可有总共k个放了两个炮的列,同时j+1个放1个炮的列也变成了j个 
    dp[i][j][k] = (dp[i][j][k] + j * (m - (j+k-1) ) * dp[i - 1][j][k - 1]) % mod;//j列任选一个,空列任选一个, 都放一个,即可有k个放了两个炮的列乘法原理。 
    dp[i][j][k] = (dp[i][j][k] + (m - j - k + 1) * dp[i - 1][j - 1][k]) % mod//空列放一个,即可有j个放了一个炮的列。 
    dp[i][j][k] = (dp[i][j][k] + C(j + 2) * dp[i - 1][j + 2][k - 2]) % mod;//j+2列里任选两个。 
    dp[i][j][k] = (dp[i][j][k] + C(m - j - k + 2) * dp[i - 1][j - 2][k]) % mod;//空列里任选两个 
    

    Code:

    #include <bits/stdc++.h>
    #define int long long	
    const int mod =  9999973;
    using namespace std;
    int n, m, ans;
    int dp[111][111][111];//三维数组dp[i][j][k]表示前i行内放了有j个只放了一个炮的列,k个放了两个炮的列的总方案数 
    int C(int n) {return ((n * (n - 1)) / 2) %mod;} //C(n, 2),n个数里面选择2个数的组合数。 
    signed main()
    {
     	scanf("%lld%lld", &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; k <= m - j; k++)
     			{
     				dp[i][j][k] = dp[i][j][k] + dp[i - 1][j][k] % mod;
     				if (k >= 1)
     					dp[i][j][k] = (dp[i][j][k] + (j + 1) * dp[i - 1][j + 1][k - 1]) % mod;//j+1个列里任选一个即可有总共k个放了两个炮的列,同时j+1个放1个炮的列也变成了j个 
    				if (k >= 1)
     					dp[i][j][k] = (dp[i][j][k] + j * (m - (j+k-1) ) * dp[i - 1][j][k - 1]) % mod;//j列任选一个,空列任选一个, 都放一个,即可有k个放了两个炮的列乘法原理。 
     				if (j >= 1)
     					dp[i][j][k] = (dp[i][j][k] + (m - j - k + 1) * dp[i - 1][j - 1][k]) % mod//空列放一个,即可有j个放了一个炮的列。 
     				if (k >= 2)
     					dp[i][j][k] = (dp[i][j][k] + C(j + 2) * dp[i - 1][j + 2][k - 2]) % mod;//j+2列里任选两个。 
     				if (j >= 2)
    	 				dp[i][j][k] = (dp[i][j][k] + C(m - j - k + 2) * dp[i - 1][j - 2][k]) % mod;//空列里任选两个 
     			}
     	for (int i = 0; i <= m; i++)
     		for (int j = 0; j <= m; j++)
     			ans += dp[n][i][j], ans %= mod;//全放两个的,全放一个的和放两个和放一个都有的,都有可能出现,所以都要加上;
     			    printf("%lld", ans % mod);
     	return 0;
    }	
    
  • 相关阅读:
    linux 计划任务
    linux 进程管理
    PHP中global与$GLOBALS['']的区别
    php预定义变量
    linux 强制终止进程命令
    mysql取某表中数据的随机的方法
    mysql 连接 选库 查询
    Python 的异步 IO:Asyncio 简介
    并发和并行的区别
    asyncio模块中的Future和Task
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/11789059.html
Copyright © 2011-2022 走看看