zoukankan      html  css  js  c++  java
  • bzoj1801[Ahoi2009]chess 中国象棋 dp

    题目描述

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

    输入格式

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

    输出格式

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

    题解

    据说三进制只有50分?(其实是我不会三进制)感觉这题就跟状压没关系了,直接dp就可以了。
    (f[i][j][k])表示第i行有j列有1个炮,有k列有2个炮。然后转移即可。情况蛮多的,总是写不全qwq。

    • 在没有炮的一列放一个
    • 在没有炮的两列各放一个
    • 在有一个炮的一列再放一个
    • 在有一个炮的两列各再放一个
    • 在有一个炮的一列再放一个,在没有炮的一列放一个

    利用组合数求解。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int mod=9999973;
    const int maxn=(1<<9)+10;
    typedef long long ll;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m;
    ll inv[110],fac[110];
    ll f[110][110][110];
    ll pow(ll a,ll b){
        ll res=1;
        while(b){
            if(b&1)res=res*a%mod;
            a=a*a%mod;
            b/=2;
        }
        return res;
    }
    ll c(ll n,ll m){
    	if(n>m)return 0; 
        return fac[m]*inv[n]%mod*inv[m-n]%mod;
    }
    void init(){
        fac[0]=1;
        for(int i=1;i<=101;i++)fac[i]=fac[i-1]*i%mod;
        inv[101]=pow(fac[101],mod-2);
        for(int i=100;i>=0;i--)inv[i]=(inv[i+1]*(i+1))%mod;
    }
    int main(){
    	init();
        n=read();m=read();
    	f[0][0][0]=1;
        for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=m;k++){
            if(f[i-1][j][k]){
                f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;
                if(j+k<m)f[i][j+1][k]=(f[i][j+1][k]+f[i-1][j][k]*(m-j-k)%mod)%mod;
                if(j+k<m-1)f[i][j+2][k]=(f[i][j+2][k]+f[i-1][j][k]*c(2,m-j-k)%mod)%mod;
    			if(j>0&&(k+1)<=m)f[i][j-1][k+1]=(f[i][j-1][k+1]+f[i-1][j][k]*j%mod)%mod;
                if(j>1&&(k+2)<=m)f[i][j-2][k+2]=(f[i][j-2][k+2]+f[i-1][j][k]*c(2,j)%mod)%mod;
                if(j>0&&(j+k)<m)f[i][j][k+1]=(f[i][j][k+1]+f[i-1][j][k]*(m-j-k)%mod*j%mod)%mod;
            }
        }
        int ans=0;
        for(int i=0;i<=m;i++) for(int j=0;j<=m;j++) 
    		ans=(ans+f[n][i][j])%mod;
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Triangle
    Pascal's Triangle II
    Pascal's Triangle
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
    [c++]this指针理解
    [oracle]一个最简单的oracle存储过程"proc_helloworld"
    Oracle 的 INSERT ALL和INSERT FIRST
    Linux2.6 内核的 Initrd 机制解析
    /boot/grub/menu.lst详解
  • 原文地址:https://www.cnblogs.com/Nan-Cheng/p/9741791.html
Copyright © 2011-2022 走看看