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

    题目描述

    这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法。大家肯定很清楚,在中国象棋中炮的行走方式是:一个炮攻击到另一个炮,当且仅当它们在同一行或同一列中,且它们之间恰好 有一个棋子。你也来和小可可一起锻炼一下思维吧!

    输入输出格式

    输入格式:

    一行包含两个整数N,M,之间由一个空格隔开。

    输出格式:

    总共的方案数,由于该值可能很大,只需给出方案数模9999973的结果。

    输入输出样例

    输入样例#1: 
    1 3
    输出样例#1: 
    7

    说明

    样例说明

    除了3个格子里都塞满了炮以外,其它方案都是可行的,所以一共有2*2*2-1=7种方案。

    数据范围

    100%的数据中N和M均不超过100

    50%的数据中N和M至少有一个数不超过8

    30%的数据中N和M均不超过6

     题解:

      前30%明显是暴力

      50%是状压,不过是3进制下的,不太好写...

      一个明显的结论是不同的列(行)之间任意交换对答案是没有影响的。所以我们可以不用记录棋子防止的具体信息。我们设f[i][j][k]表示前i列有j列放了一个棋子、k列放了两个棋子的方案数。

      那么再考虑这个状态能由哪些状态转移过来。

      首先是第i列一个棋子也不放,那么f[i][j][k] = f[i-1][j][k]

      其次是放一个,这时有两种情况;最后是放两个,有三种情况。请读者自己思考=-=

     1 // f[i][j][k]表示前i行中有j列放了1个炮,k列放了两个炮的种类数 
     2 // f[i][j][k] = f[i-1][j][k] (一个都不放 
     3 //            + f[i-1][j-1][k]*(m-j-k+1) + f[i-1][j+1][k-1]*(j+1)  (放1个 
     4 //              + f[i-1][j-2][k]*C(m-j-k+2,2) + f[i-1][j][k-1]*j*(m-j-k+1) + f[i-1][j+2][k-2]*C(j+2,2) (放2个 
     5 #include<iostream>
     6 #include<cstdio>
     7 #include<cstring>
     8 #define LL long long
     9 #define RI register int
    10 #define KI 9999973
    11 using namespace std;
    12 const int INF = 0x7ffffff ;
    13 const int N = 100 + 10 ;
    14 
    15 inline int read() {
    16     int k = 0 , f = 1 ; char c = getchar() ;
    17     for( ; !isdigit(c) ; c = getchar())
    18       if(c == '-') f = -1 ;
    19     for( ; isdigit(c) ; c = getchar())
    20       k = k*10 + c-'0' ;
    21     return k*f ;
    22 }
    23 int n, m ; LL f[N][N][N] ;
    24 
    25 inline LL C(int x,int y) { return (x*(x-1)>>1)%KI ; }   // y都是2 
    26 int main() {
    27     n = read(), m = read() ;
    28     f[1][0][0] = 1 ; f[1][1][0] = m ; f[1][2][0] = C(m,2) ;
    29     for(int i=2;i<=n;i++) {
    30         for(int j=0;j<=m;j++) {
    31             for(int k=0;k<=m-j;k++) {
    32                 f[i][j][k] = f[i-1][j][k] ;
    33                 if(j) f[i][j][k] += f[i-1][j-1][k]*(m-j-k+1), f[i][j][k] %= KI ;
    34                 if(k && j < m) f[i][j][k] += f[i-1][j+1][k-1]*(j+1), f[i][j][k] %= KI ;
    35                 if(j > 1) f[i][j][k] += f[i-1][j-2][k]*C(m-j-k+2,2), f[i][j][k] %= KI ;
    36                 if(k) f[i][j][k] += f[i-1][j][k-1]*j*(m-j-k+1), f[i][j][k] %= KI ;
    37                 if(k > 1 && j < m-1) f[i][j][k] += f[i-1][j+2][k-2]*C(j+2,2), f[i][j][k] %= KI ;
    38             }
    39         }
    40     }
    41     int ans = 0 ;
    42     for(int j=0;j<=m;j++) {
    43         for(int k=0;k<=m-j;k++) ans += f[n][j][k], ans %= KI ;
    44     }
    45     printf("%d",ans) ;
    46     return 0 ;
    47 }

     

  • 相关阅读:
    人月神话阅读笔记01
    个人每日总结14
    个人每日总结13
    个人每日总结12
    个人每日总结11
    个人每日总结10
    个人每日总结9
    第五周学习进度表
    梦断代码阅读笔记
    05构建之法阅读笔记之五
  • 原文地址:https://www.cnblogs.com/zub23333/p/8717378.html
Copyright © 2011-2022 走看看