题目
一个长度为k的整数序列b1,b2,…,bk(1≤b1≤b2≤…≤bk≤N)称为“好序列”当且仅当后一个数是前一个数的倍数,即bi+1是bi的倍数对任意的i(1≤i≤k-1)成立。
给定N和k,请算出有多少个长度为k的“好序列”,答案对1000000007取模。
(1<=n,k<=2000)
题解
DP,
f[i,j]表示长度为i的末尾为j的好序列的个数
方程=
f[i,j]=∑f[i,x] (x为j的约数)
由于n和k都比较大,可以想到运用动态规划
设f(i,j)表示序列的前i个数已经确定,并且最后一个数为j的方案数
因为后一个数必须是前一个数的倍数,因此
f(i,j)=Σf(i,x) x为j的约数
可以预先处理处约数
还可考虑,用“正向思维法”对动态规划进行改造:对于当前的状态f(i,j),可以“贡献”哪些状态?f[i+1,j*x] (j*x<=n
时间复杂度O(kn log n)
代码
方法一:
var
n,k,i,j,ans,t:longint;
f,a:array[0..2000,0..2000]of longint;
begin
readln(n,k);
for i:=1 to n do
for j:=1 to trunc(sqrt(i)) do
if i mod j=0 then
begin
inc(a[i,0]);
a[i,a[i,0]]:=j;
if i div j<>j then
begin
inc(a[i,0]);
a[i,a[i,0]]:=i div j;
end;
end;
for i:=1 to n do
f[0,i]:=1;
for i:=1 to k do
for j:=1 to n do
for t:=1 to a[j,0] do
f[i,j]:=(f[i,j]+f[i-1,a[j,t]]) mod 1000000007;
for i:=1 to n do
f[k,0]:=(f[k,0]+f[k-1,i]) mod 1000000007;
writeln(f[k,0]);
end.
方法二:
var
i,j,k,l,n,ans:longint;
f:array[1..2000,1..2000]of longint;
begin
readln(n,k);
for i:=1 to n do
f[1,i]:=1;
for i:=1 to k do
for j:=1 to n do
for l:=1 to n div j do
f[i+1,j*l]:=(f[i+1,j*l]+f[i,j]) mod 1000000007;
for i:=1 to n do
ans:=(ans+f[k,i]) mod 1000000007;
writeln(ans);
end.