【2020.9.12模拟赛】【SSL校网2】1138. 序列

时间限制:1000MS内存限制:128000KB


题目描述
一个长度为k的整数序列 b 1 , b 2 , … , b k b1,b2,…,bk b1b2bk ( 1 ≤ b 1 ≤ b 2 ≤ … ≤ b k ≤ N ) (1≤b1≤b2≤…≤bk≤N) 1b1b2bkN称为“好序列”当且仅当后一个数是前一个数的倍数,即 b i + 1 bi+1 bi+1 b i bi bi的倍数对任意的 i ( 1 ≤ i ≤ k − 1 ) i(1≤i≤k-1) i1ik1成立。
给定N和k,请算出有多少个长度为k的“好序列”,答案对 1000000007 1000000007 1000000007取模。


输入

输入共1行,包含2个用空格隔开的整数N和k。

输出

输出共1行,包含一个整数,表示长度为k的“好序列”的个数对 1000000007 1000000007 1000000007取模后的结果。


输入样例复制
3 2

输出样例复制
5


说明

【输入输出样例说明】
“好序列”为: [ 1 , 1 ] , [ 1 , 2 ] , [ 1 , 3 ] , [ 2 , 2 ] , [ 3 , 3 ] [1,1],[1,2],[1,3],[2,2],[3,3] [1,1][1,2][1,3][2,2][3,3]

【数据说明】
对于 40 40 40%的数据, 1 ≤ N ≤ 30 , 1 ≤ k ≤ 10 1≤N≤30,1≤k≤10 1N301k10
对于 100 100 100%的数据, 1 ≤ N ≤ 2000 , 1 ≤ k ≤ 2000 1≤N≤2000,1≤k≤2000 1N20001k2000


解题思路
我们先预处理出每个数字在序列中存在的倍数,设b[i][j]为第i个数第j个倍数是多少。
我们设 f [ j ] f[j] f[j]为开头数字为j时有多少个序列,输出时将 f [ 1   n ] f[1~n] f[1 n]累加就好了。。

然后来举个例子:
n = 4 , k = 1 n=4,k=1 n=4k=1时,
f [ 1 f[1 f[1~ 4 ] = 1 , 1 , 1 , 1 4]=1,1,1,1 4]=1111
n = 4 , k = 2 n=4,k=2 n=4k=2时,
f [ 1 f[1 f[1~ 4 ] = 4 , 2 , 1 , 1 4]=4,2,1,1 4]=4211
n = 4 , k = 3 n=4,k=3 n=4k=3时,
f [ 1 f[1 f[1~ 4 ] = 8 , 3 , 1 , 1 4]=8,3,1,1 4]=8311

我们会发现:这一行 f [ j ] f[j] f[j]等于上一行的 f [ j ] f[j] f[j],加上,上一行中的 f [ j 的 倍 数 ] f[j的倍数] f[j]
例:第二行的 f [ 1 ] = 1 + 1 + 1 + 1 f[1]=1+1+1+1 f[1]=1+1+1+1,第二行的 f [ 2 ] = 1 + 1 f[2]=1+1 f[2]=1+1,第三行的 f [ 1 ] = 4 + 2 + 1 + 1 f[1]=4+2+1+1 f[1]=4+2+1+1,第三行的 f [ 2 ] = 2 + 1 f[2]=2+1 f[2]=2+1

其实可以这么理解:你在一个正确的序列前加了一个数,这个数是那个序列的第一个数的因数。


代码

#include<bits/stdc++.h>
using namespace std;
const int INF=1000000007;
int n,k,ans,t,b[3000][3000],f[3000],ff[3000];
int main(){
     
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
     
		f[i]=1;
		for(int j=i+1;j<=n;j++)
		{
     
			if(j%i==0)
				b[i][++b[i][0]]=j;	
		}
	}
	for(int i=2;i<=k;i++)
	{
     
		for(int j=n;j>0;j--)
		{
     
			t=f[j];
			for(int s=1;s<=b[j][0];s++)
			{
     
				t=(t+f[b[j][s]])%INF;
			}
			ff[j]=t;
		}
		for(int j=1;j<=n;j++)
			f[j]=ff[j];	
	}
	for(int i=1;i<=n;i++)
		ans=(ans+f[i])%INF;
	printf("%d",ans);
}

你可能感兴趣的:(数学)