zoukankan      html  css  js  c++  java
  • BZOJ1801 Ahoi2009 chess 中国象棋 【DP+组合计数】*

    BZOJ1801 Ahoi2009 chess 中国象棋


    Description

    在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。 请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧.

    Input

    一行包含两个整数N,M,中间用空格分开.

    Output

    输出所有的方案数,由于值比较大,输出其mod 9999973

    Sample Input

    1 3

    Sample Output

    7

    HINT

    除了在3个格子中都放满炮的的情况外,其它的都可以.
    100%的数据中N,M不超过100
    50%的数据中,N,M至少有一个数不超过8
    30%的数据中,N,M均不超过6


    不难发现每行每列最多只有2个棋子
    考虑DP,dpi,j,kdp_{i,j,k}dpi,j,k表示i行中一共有j列有一个,k列有两个
    然后我们考虑这一行选多少

    • 当前行不选
      dpi,j,k=dpi−1,j,k
    • 当前行选一个
      • 选原来是0个棋子dp(i,j,k)+=dp(i−1,j−1,k)∗c(n−k−j+1,1)(1≤j)
      • 选原来是1个棋子dp(i,j,k)+=dp(i−1,j+1,k−1)∗c(j+1,1)(1≤k,j≤m−1)
    • 当前行选两个
      • 选两个原来是0的dp(i,j,k)+=dp(i−1,j−2,k)*c(m-j-k+1,2)(2≤j)
      • 选两个原来是1的dp(i,j,k)+=dp(i−1,j+2,k−2)*c(j+2,2)(2≤k,j≤m−2)
      • 选一个是1一个是0 dp(i,j,k)+=dp(i−1,j,k−1)*j*(m-j-k+1)(1≤j,1≤k(要保证原来有1))

    然后就可以进行转移了


     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define fu(a,b,c) for(int a=b;a<=c;++a)
     4 #define fd(a,b,c) for(int a=b;a>=c;--a)
     5 #define N 110
     6 #define LL long long
     7 #define Mod 9999973
     8 LL c[N][N];
     9 LL dp[N][N][N]={0};
    10 int n,m;
    11 void getc(){
    12   fu(i,0,N-1)c[i][0]=1;
    13   fu(i,1,N-1)
    14     fu(j,1,i)c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
    15 }
    16 LL mul(LL a,LL b){return a*b%Mod;}
    17 int main(){
    18   getc();
    19   dp[0][0][0]=1;
    20   scanf("%d%d",&n,&m);
    21   if(n<m)swap(n,m);
    22   fu(i,1,n)
    23     fu(j,0,m)
    24       fu(k,0,m-j){
    25         dp[i][j][k]=dp[i-1][j][k];
    26         if(j)dp[i][j][k]+=mul(dp[i-1][j-1][k],c[m-j-k+1][1]);
    27         if(j&&k)dp[i][j][k]+=mul(dp[i-1][j][k-1],mul(j,m-j-k+1));
    28         if(j>=2)dp[i][j][k]+=mul(dp[i-1][j-2][k],c[m-j-k+2][2]);
    29         if(k>=1&&j<=m-1)dp[i][j][k]+=mul(dp[i-1][j+1][k-1],c[j+1][1]);
    30         if(k>=2&&j<=m-2)dp[i][j][k]+=mul(dp[i-1][j+2][k-2],c[j+2][2]);
    31         dp[i][j][k]%=Mod;
    32       }
    33   int ans=0;
    34   fu(i,0,m)
    35     fu(j,0,m-i)
    36       ans=(ans+dp[n][i][j])%Mod;
    37   printf("%d",ans);
    38   return 0;
    39 }
  • 相关阅读:
    LeetCode #4 中等题(二分,中位数)
    LeetCode #3 简单题(map标记)
    leetCode #2 简单题(链表)
    LeetCode #1 简单题(map存一下基本就O(nlogn)复杂度)
    CMake使用入门笔记( 1 ) BuildSystem的三个指令 --- 更新中
    (模拟)hihocoder
    (暴力)UVA
    (IDA*)HDU
    总结
    (模拟+贪心)codeforces
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676238.html
Copyright © 2011-2022 走看看