• 洛谷 2051 [AHOI2009] 中国象棋


    这也是一道dp方程很难想出来的dp

    要是想通了方程,后续的推导也需要花费一定的时间,所以是一道好题

    我直接讲dp方程吧

    因为我也没有想出来dp方程,是某个同学告诉我的

    dp[i][j][k]表示到了第i行,这一行之前有j列放了1个棋子,有k列放了2个棋子

    这个方程确实不好想

    转移有一点多

    总共有6个转移方程

    其实是压了一维,这一维是放了0个棋子的列数

    因为这一维可以由其他两维推出他就=m-j-k;

    dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k])%mod;

    表示这一行什么棋子也不取

    dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k]*(m-j-k+1))%mod;

    表示这一行将之前的一个0个全变成1个有多少种方案

    就是由j-1在加上了这个变来得1

    dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k-1]*(j+1))%mod;

    表示这一行将之前的一个1全变成2有多少种方案

    由j+1减去了1,k-1加上了1

    dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-2][k]*calc(m-j-k+2))%mod;

    这是将之前的2个0全都变成1

    因为可以任取2个,所以运用组合数就是C(m-j-k+2,2)

    dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+2][k-2]*calc(j+2))%mod;

    这是将之前的2个1全变成2

    通过组合数同样是C(j+2,2)

    dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1]*(m-j-k+1)*j)%mod;

    这里表示将之前的1个0变成1,一个1变成2

    j-1加上当前由0变成的1就是j,再将两个方案乘起来

    这就是所有的6个方程

    代码如下

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <cstring>
     6 using namespace std;
     7 typedef long long ll;
     8 const ll mod=9999973;
     9 const ll N=105;
    10 ll dp[N][N][N],n,m;
    11 ll calc(ll x)
    12 {
    13     return (x*(x-1)/2)%mod;
    14 }
    15 int main()
    16 {
    17     scanf("%lld %lld",&n,&m);
    18     dp[0][0][0]=1;
    19     for(ll i=1;i<=n;i++)
    20     for(ll j=0;j<=m;j++)
    21     for(ll k=0;k<=m-j;k++)
    22     {
    23         dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k])%mod;// 1
    24         if(m-j-k+1>=0 && j>=1)
    25             dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k]*(m-j-k+1))%mod;// 2
    26         if(j+1>=0 && k>=1)
    27             dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k-1]*(j+1))%mod;//   3
    28         if(m-j-k+2>=0 && j>=2)
    29             dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-2][k]*calc(m-j-k+2))%mod;//4
    30         if(j+2>=0 && k>=2)
    31             dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+2][k-2]*calc(j+2))%mod;//  5
    32         if(m-j-k+1>=0 && k>=1 && j>=1)
    33             dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1]*(m-j-k+1)*j)%mod;//  6
    34     }
    35     ll ans=0;
    36     for(int j=0;j<=m;j++)
    37         for(int k=0;k+j<=m;k++)
    38         {
    39             ans=(ans+dp[n][j][k])%mod;
    40         }
    41     printf("%lld
    ",ans);
    42     return 0;
    43 }
  • 相关阅读:
    实验4:开源控制器实践——OpenDaylight
    实验3:OpenFlow协议分析实践
    实验2:Open vSwitch虚拟交换机实践
    第一次个人编程作业
    SDN实验1:SDN拓扑实践
    第一次博客作业
    LeetCode-1290.Convert Binary Number in a Linked List to Integer
    面试题 02.02. Kth Node From End of List LCCI
    剑指 Offer 24. 反转链表
    剑指 Offer 06. 从尾到头打印链表
  • 原文地址:https://www.cnblogs.com/wzrdl/p/9802084.html
Copyright © 2020-2023  润新知