Description
找到一个数组的最大值的一种方法是从数组开头从前到后对数组进行扫描,令max=a[0] (数组下表从0..N-1),如果a[i]>max,就更新max,这样就可以在O(N)的时间里找到一个数组的最大值。
这个问题是相当简单的,但是想到了另一个问题,如果一个包含N个元素的数组a里面的元素的值是在1…K之间的整数,存在多少个不同的数组a,进行了如上扫描之后,max恰好进行了P次更新?
下面是N = 4,K = 3,P = 2时所有情况
1) {1,1,2,3}
2) {1,2,1,3}
3) {1,2,2,3}
4) {1,2,3,1}
5) {1,2,3,2}
6) {1,2,3,3}
共有6种情况
由于答案可能很大,所以你仅仅需要把答案mod (10^9+7)输出。
Input
输入文件findmax.in的第一行T,本题有T组数据。
接下来T行,每行三个整数N,K,P
Output
输出文件findmax.out包括T行,每行一个答案。
题解
用DP做的,数组f[i,j,k]表示i位之前最大的数为j,并且已经更新了k次的方案数。
那么f[i,j,k]=f[i-1,q,k-1]+f[i-1,j,k]*j,其中q为所有小于j数字。
因为当我们在最后一位加入j时,所有第i位之前最大的数比j小的方案都会更新一次,所以要加上所有的f[i-1,q,k-1],q要小于k。
如果第i位之前最大的数已经为j,则本次不会更新,但第i位可以填入任何比j小的数,所以加上f[i-1,j,k]*j。
最后输出的答案为i=n,k=p时j从1到m的所有方案数。
裸的话会超时,用前缀和优化一下第二步。
空间方面可以用滚动数组。
代码
const
mood=1000000007;
var
t,n,m,p:longint;
f,b:array [0..301,0..101] of int64;
ans:int64;
function min(o,p:longint):longint;
begin
if o<p then exit(o);
exit(p);
end;
procedure main;
var
i,j,k,l:longint;
begin
for l:=1 to t do
begin
fillchar(f,sizeof(f),0);
fillchar(b,sizeof(b),0);
readln(n,m,p);
for i:=1 to m do
begin
f[i,0]:=1; b[i,0]:=i;
end;
for i:=2 to n do
for k:=min(i-1,p) downto 0 do
for j:=1 to m do
begin
f[j,k]:=(f[j,k]*j) mod mood;
if k>0 then
f[j,k]:=(f[j,k]+b[j-1,k-1]) mod mood;
b[j,k]:=b[j-1,k]+f[j,k];
end;
ans:=0;
for i:=1 to m do
ans:=(ans+f[i,p]) mod mood;
writeln(ans);
end;
end;
begin
readln(t);
main;
end.