码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj2699】更新 dp

时间:2017-11-07 22:20:00      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:log   int   printf   次数   pre   scanf   优化   return   nbsp   

题目描述

对于一个数列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]=\sum\limits_{l=1}^{k-1}f[i-1][j-1][l]$ 。

因此使用前缀和 $sum[i][j][k]=\sum\limits_{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\n" , sum[x][z + 1][y]);
	return 0;
}

 

【bzoj2699】更新 dp

标签:log   int   printf   次数   pre   scanf   优化   return   nbsp   

原文地址:http://www.cnblogs.com/GXZlegend/p/7800913.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!