zoukankan      html  css  js  c++  java
  • 【bzoj2699】更新 dp

    题目描述

    对于一个数列A[1..N],一种寻找最大值的方法是:依次枚举A[2]到A[N],如果A[i]比当前的A[1]值要大,那么就令A[1]=A[i],最后A[1]为所求最大值。假设所有数都在范围[1, K]内,按上面的步骤执行,有多少个长度N的数列满足A[1]被更新的次数恰好为P呢?

    输入

    本题有多组数据。输入第一行一个数T为数据组数,下面T行每行依次三个数N、K和P。

    输出

    对每组数据输出一行,为方案数模1000000007的值。

    样例输入

    3
    4 3 2
    2 3 1
    3 4 1

    样例输出

    6
    3
    30


    题解

    dp

    设 $f[i][j][k]$ 表示 $i$ 个数,更新次数为 $j$ ,最大值为 $k$ 的方案数。

    那么考虑第 $i$ 个数是否对最大值产生更新来进行转移:

    当不产生更新时,前面最大值为 $k$ ,第 $i$ 个数的取值范围为 $[1,k]$ ,因此 $f[i][j][k]=f[i-1][j][k]*k$ ;

    当产生更新时,前面最大值取值范围为 $[1,k-1]$ ,第 $i$ 个数的取值为 $k$ ,因此 $f[i][j][k]=sumlimits_{l=1}^{k-1}f[i-1][j-1][l]$ 。

    因此使用前缀和 $sum[i][j][k]=sumlimits_{l=1}^kf[i][j][l]$ 来优化dp转移,即可预处理出所有的dp值。

    最后对于每个询问直接输出答案即可。

    时间复杂度 $O(npk)$

    #include <cstdio>
    #define mod 1000000007
    long long sum[155][155][310];
    int main()
    {
    	int i , j , k , T , x , y , z;
    	for(i = 1 ; i <= 300 ; i ++ ) sum[1][1][i] = i;
    	for(i = 2 ; i <= 150 ; i ++ )
    		for(j = 1 ; j <= 150 ; j ++ )
    			for(k = 1 ; k <= 300 ; k ++ )
    				sum[i][j][k] = (sum[i][j][k - 1] + sum[i - 1][j - 1][k - 1] + (sum[i - 1][j][k] - sum[i - 1][j][k - 1]) * k % mod + mod) % mod;
    	scanf("%d" , &T);
    	while(T -- ) scanf("%d%d%d" , &x , &y , &z) , printf("%lld
    " , sum[x][z + 1][y]);
    	return 0;
    }
    
  • 相关阅读:
    窗口设置背景图片
    双链表
    单链表
    Hough直线检测
    轮廓跟踪
    轮廓提取
    基于腐蚀的二值图像距离变换
    创建对话框用于交互
    hello world
    c#---params参数
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7800913.html
Copyright © 2011-2022 走看看