1. 程式人生 > >bzoj 1801: [Ahoi2009]chess 中國象棋

bzoj 1801: [Ahoi2009]chess 中國象棋

std stream 一個數 space 兩個 blog mat 多少 並且

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

Source

Day2

通過象棋的規則,每行每列最多兩個炮。。

那麽每行最多放兩個,並且不能放在已經有兩個炮的列上。。

那麽設dp[i][j][k]表示到了第i行,有j列沒有放,有k列只放了一個炮的方案數。。。

那麽對於每一行,可以用組合數大力討論這[0,2]個炮怎麽放,總共6種情況,然後加法原理加起來。。。

暴力得不行。。。

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=100050;
const int Mod=9999973;
ll jc[N],inv[N],dp[105][105][105],n,m;
ll qpow(ll a,ll b){ll ans=1;while(b){if (b&1) (ans*=a)%=Mod;(a*=a)%=Mod,b>>=1;}return ans;}
ll C(int n,int m){
  return jc[n]*inv[m]%Mod*inv[n-m]%Mod;
}
int main(){
  scanf("%d%d",&n,&m);
  jc[0]=1;for(int i=1;i<=m;i++) (jc[i]=jc[i-1]*i)%=Mod;
  for(int i=0;i<=m;i++) inv[i]=qpow(jc[i],Mod-2);
  dp[0][m][0]=1;
  for(int i=1;i<=n;i++){
    for(int j=0;j<=m;j++){
      for(int k=0;k<=m;k++){
    (dp[i][j][k]+=dp[i-1][j][k])%=Mod;
    if(k-1>=0) (dp[i][j][k]+=C(j+1,1)*dp[i-1][j+1][k-1])%=Mod;
    if(k-2>=0) (dp[i][j][k]+=C(j+2,2)*dp[i-1][j+2][k-2])%=Mod;
    (dp[i][j][k]+=C(k+1,1)*dp[i-1][j][k+1])%=Mod;
    (dp[i][j][k]+=C(k+2,2)*dp[i-1][j][k+2])%=Mod;
    (dp[i][j][k]+=C(j+1,1)*C(k,1)%Mod*dp[i-1][j+1][k])%=Mod;
      }
    }
  }
  ll ans=0;
  for(int i=0;i<=m;i++)
    for(int j=0;j<=m;j++)(ans+=dp[n][i][j])%=Mod;
  printf("%lld\n",ans);
  return 0;
}

  

bzoj 1801: [Ahoi2009]chess 中國象棋