zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    启用oracle 11g自己主动收集统计信息
    在java中,怎样跳出当前的多重循环?
    从编程的角度理解gradle脚本﹘﹘Android Studio脚本构建和编程[魅族Degao]
    【SpringMVC架构】SpringMVC入门实例,解析工作原理(二)
    实现icon和文字垂直居中的两种方法-(vertical-align and line-height)
    android发送get请求时报错
    KeyEvent 键码值
    Android-黑科技-微信抢红包必备软件
    Delicious Apples (hdu 5303 贪心+枚举)
    vim 插件配置博客记录
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7212226.html
Copyright © 2011-2022 走看看