• 【NOIP模拟】table(动态规划)


    题目背景

    SOURCE:NOIP2016-RZZ-2 T2

    题目描述

    给定一个 n×m 的矩阵,行列均从 1 开始标号。

    一个矩阵被认为是稳定的,当且仅当对于任意的 2≤i≤n,第 i 行的数的和不小于第 i−1 行的数的和,且最后一行的数的和小于等于 m ,并且要求矩阵中所有的元素都是非负的。

    求所有 n×m 的稳定矩阵的方案数,答案对 109 取模。

    输入格式

    第一行一个整数 T ,表示数据组数。
    每组数据一行两个整数 n,m 。

    输出格式

    输出 T 行,每行一个整数,表示方案数。

    样例数据 1

    输入


    1 1 
    2 2 
    2 3

    输出


    25 
    273

    备注

    【数据规模与约定】

    对于 30% 的数据,n,m≤3。
    对于 60% 的数据,n,m≤50。
    对于 100% 的数据,1≤n,m≤2000;1≤T≤10。

    【题目分析】

      题目意思显而易见,求两次dp:

      第一次,求出$C(i, j)$:

        对于这一次dp,其实就是求组合数,可以使用递推公式: $$C(i, j) = C(i - 1, j - 1) + C(i - 1, j)$$

        那么我们在求将$i$个数和为$j$的方案数时, 实际就是将$j$个1分成$i$份,可以看作从$j + i - 1$个数中选出$i - 1$个数(作为栅栏将1隔开)

        其实就是求$C(j + i - 1, i - 1)$

      第二次,求出$dp(i, j)$表示第$i$行和小于等于$j$的方案数。

        这一次dp采用前缀和累加记录。对于当前$dp(i, j)$, 先加上$dp(i, j - 1)$(累加,这样算出来的才是小于等于j的方案数),

        然后再加上$C(j + m - 1,m - 1) × dp(i - 1, j)$(上一行的和小于等于当前行的和, 则当前行的和为$j$时(方案数$C(j + m - 1,m - 1)$) ×上一行的和小于等于$j$(方案数$dp(i - 1, j)$).

        不要忘记取模(乘法爆int 先乘上 1LL )。

     

     

    【code】

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int N = 2005, Mod = 1e9;
    int n, m, T;
    int cnt[N<<1][N<<1], s[N][N];
    
    inline void init(){
        for(int i = 0; i <= 4000; i++) cnt[i][0] = cnt[i][i] = 1;
        for(int i = 2; i <= 4000; i++)
            for(int j = 1; j < i; j++)
                cnt[i][j] = (cnt[i - 1][j - 1] + cnt[i - 1][j]) % Mod;
    }
    
    int main(){
        init();
    //    cout<<sum[2][2]<<" "<<sum[2][1]<<" "<<sum[2][0];return 0;
        cin>>T;
        while(T--){
            cin>>n>>m;
            memset(s, 0, sizeof s);
            for(int i = 0; i <= m; i++) s[0][i] = 1;
            for(int i = 1; i <= n; i++){
                for(int j = 0; j <= m; j++){
                    long long tmp = s[i - 1][j];
                    tmp = (1LL * tmp * cnt[j + m - 1][m - 1]) % Mod;
                    if(j) s[i][j] = (tmp + s[i][j - 1]) % Mod;
                    else s[i][j] = tmp;
                }
            }
            cout<<s[n][m]<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    5.Makefile的原理及应用
    8.adr与ldr伪指令的区别
    6.反汇编的原理
    9.S5PV210的时钟系统
    1.No MBR错误
    4.交叉编译工具链的安装及使用
    Java角度制向弧度制转化
    Java小题,通过JNI调用本地C++共享库中的对应方法实现杨辉三角的绘制
    编译安装-PHP
    编译安装-MySQL5.5
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7212226.html
Copyright © 2020-2023  润新知