DP,递推,组合数

其实相当于就是一个递推推式子,然后要用到一点组合数的知识

一道很妙的题,因为不能互相攻击,所以任意行列不能有超过两个炮

首先令f[i][j][k]代表前i行,有j列为一个炮,有k列为两个炮的方案

那么有如下转移:

1,这行不放炮,add+=f[i-1][j][k];

2,放一个炮,并且放在没有炮的那列 add+=f[i-1][j-1][k] * (m - j - k + 1);,因为放了这个炮后,

一个炮的变多了,也就是上一行的j+1得到这一行的j,所以上一行的j就是j-1,

又因为有m - (j - 1) - k列没有炮的,所以有乘上m- j - k + 1种方案

3,放一个炮,并且放在原先有一个炮的那列,add+=f[i-1][j+1][k-1] * (j + 1);

放了这个炮后,一个炮的变少了一个,两个炮的变多了一个,所以还回去就是j+1,k-1,

又因为有j+1列一个炮的,所以有j+1种方案放置

4,放两个炮,都放在没有炮的列上面,add+=f[i-1][j-2][k] * (m - j - k + 2) * (m - j - k + 1) / 2;

那么放了炮后,一个炮的变多了2列,所以还回去是j-2,又因为有(m - j - k + 2)列空的,所以就是在这些里面选两个组合,所以组合数计算

5,放两个炮,分别放在有炮的和没有炮的,add+=f[i-1][j][k-1] * (m - j - k + 1) * j;

因为没有炮 --- > 1个炮 ---> j++

一个炮 ---> 2个炮 ---> j--,k++

相当于j没有变化,而k要还回去,所以是f[i-1][j][k-1]

又因为有(m - j - k + 1)列空的,j列一个炮的,所以相乘得到方案

6,放两个炮,都放在原来有炮的,add+=f[i-1][j+2][k-2] * (j + 2) * (j + 1) / 2;

放了炮后,j-=2,k+=2,所以还回去就是j+2,k-2,

又因为有j+2列一个炮,选两个组合,所以就是(j + 2) * (j + 1) / 2

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define R register int
  4. #define mod 9999973
  5. #define AC 110
  6. #define LL long long
  7. int n,m,ans;
  8. LL f[AC][AC][AC];
  9. void work()
  10. {
  11. scanf("%d%d",&n,&m);
  12. f[][][]=;
  13. for(R i=;i<=n;i++)//枚举行
  14. for(R j=;j<=m;j++)//枚举一个炮有多少列
  15. {
  16. int all=m-j;//因为要保证j+k<=m
  17. for(R k=;k<=all;k++)//枚举两个炮有多少列
  18. {
  19. LL add=;//用一个变量存增量,避免多次访问3维数组,也许可以加速?
  20. add+=f[i-][j][k];
  21. if(j) add+=f[i-][j-][k] * (m - j - k + );
  22. if(k && j + <= m) add+=f[i-][j+][k-] * (j + );//有j+1列一个炮可以选
  23. if(j - >= ) add+=f[i-][j-][k] * (m - j - k + ) * (m - j - k + ) / ;
  24. if(k - >= ) add+=f[i-][j][k-] * (m - j - k + ) * j;
  25. if(j + <= m && k - >= ) add+=f[i-][j+][k-] * (j + ) * (j + ) / ;
  26. if(add > mod) add%=mod;
  27. f[i][j][k]=add;
  28. }
  29. }
  30. for(R j=;j<=m;j++)//枚举最后的情况是怎么样的
  31. {
  32. int all=m-j;
  33. for(R k=;k<=all;k++)
  34. ans=(ans + f[n][j][k])%mod;
  35. }
  36. printf("%d\n",ans);
  37. }
  38.  
  39. int main()
  40. {
  41. freopen("in.in","r",stdin);
  42. work();
  43. fclose(stdin);
  44. return ;
  45. }

[AHOI2009]中国象棋 DP,递推,组合数的更多相关文章

  1. [BZOJ1801][AHOI2009]中国象棋(递推)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1801 分析: 只会50的状态压缩…… 然后搜了下题解,发现是dp 首先易得每行每列至多 ...

  2. Luogu P2051 [AHOI2009]中国象棋(dp)

    P2051 [AHOI2009]中国象棋 题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个 \(N\) 行 \(M\) 列的棋盘上,让你放若干个炮(可以是 \(0\) 个),使得没有一个炮 ...

  3. [P2051 [AHOI2009]中国象棋] DP

    https://www.luogu.org/problemnew/show/P2051 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一 ...

  4. P2051 [AHOI2009]中国象棋——DP(我是谁,我在哪,为什么)

    象棋,给你棋盘大小,然后放炮(炮的数量不限),不能让炮打到其他的炮,问方案数: 数据n,m<=200; 状态压缩似乎能做,但是我不会: 因为只要状态数,所以不必纠结每种状态的具体情况: 可以想出 ...

  5. Luogu 2051[AHOI2009]中国象棋 - DP

    Description 在 $n * m$ 的格子上放若干个炮, 使得每个炮都不能攻击到其他炮 Solution 定义数组f[ i ][ j ][ k ] 表示到了第 i 行, 已经有2个炮的列数为 ...

  6. 洛谷P2051 [AHOI2009]中国象棋(dp)

    题面 luogu 题解 \(50pts:\)显然是\(3\)进制状压\(dp\) \(100pts:\) 一行一行地考虑 \(f[i][j][k]\)表示前\(i\)行,有\(j\)列放了一个,有\( ...

  7. 洛谷.2051.[AHOI2009]中国象棋(DP)

    题目链接 /* 每行每列不能超过2个棋子,求方案数 前面行对后面行的影响只有 放了0个.1个.2个 棋子的列数,与排列方式无关 所以设f[i][j][k]表示前i行,放了0个棋子的有j列,放了1个棋子 ...

  8. 洛谷 P2051 [AHOI2009]中国象棋 状态压缩思想DP

    P2051 [AHOI2009]中国象棋 题意: 给定一个n*m的空棋盘,问合法放置任意多个炮有多少种情况.合法放置的意思是棋子炮不会相互打到. 思路: 这道题我们可以发现因为炮是隔一个棋子可以打出去 ...

  9. [Luogu P2051] [AHOI2009]中国象棋 (状压DP->网格DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P2051 Solution 看到这题,我们不妨先看一下数据范围 30pt:n,m<=6 显然搜索,直接 ...

随机推荐

  1. jenkins通过maven指定testng的xml文件,并给testng代码传参

    1.jenkins设置参数化构建,设置要传的参数名和值 2.指定testng的xml文件,在jenkins的输入以下 3.在pom.xml文件分别引用jenkins的参数,设置两个property & ...

  2. oracle_列转行

    wmsys.wm_concat 将表中数据 如   ID   USERNAME    TYPE 1        刘                    下 1        刘           ...

  3. WPF & EF & Prism useful links

    Prism Attributes for MEF https://msdn.microsoft.com/en-us/library/ee155691%28v=vs.110%29.aspx Generi ...

  4. sql注入记录------类型转换错误---convert()函数,一句话图片马制作

    sql注入在联合查询是出现一下错误查不到数据 Illegal mix of collations for operation 'UNION' 用convert() 转换编码为utf8 或者big5 就 ...

  5. lintcode413 反转整数

    反转整数   将一个整数中的数字进行颠倒,当颠倒后的整数溢出时,返回 0 (标记为 32 位整数). 您在真实的面试中是否遇到过这个题? Yes 样例 给定 x = 123,返回 321 给定 x = ...

  6. lintcode407 加一

    加一 给定一个非负数,表示一个数字数组,在该数的基础上+1,返回一个新的数组. 该数字按照大小进行排列,最大的数在列表的最前面. 您在真实的面试中是否遇到过这个题? Yes 样例 给定 [1,2,3] ...

  7. 376. Binary Tree Path Sum【LintCode java】

    Description Given a binary tree, find all paths that sum of the nodes in the path equals to a given ...

  8. C#通过gridview导出excel

    [CustomAuthorize]        public FileResult ExportQuestionCenterExcel(SearchBaseQuestion search)      ...

  9. Centos6设置DNS

    通过编辑 vi /etc/resolv.conf 设置首选DNS和次要DNS.如下,排在前面的就是首选DNS,后面一行就是次要的DNS服务器DNS vi /etc/resolv.conf namese ...

  10. POJ 2455 Secret Milking Machine(最大流+二分)

    Description Farmer John is constructing a new milking machine and wishes to keep it secret as long a ...