题目链接: http://codeforces.com/problemset/problem/414/B
题意: A sequence of l integers b1, b2, ..., bl (1 ≤ b1 ≤ b2 ≤ ... ≤ bl ≤ n) is called good if each number divides (without a remainder) by the next number in the sequence. More formally for all i (1 ≤ i ≤ l - 1).
接收用户输入的两个整数 n, k (1 ≤ n, k ≤ 2000),从 1~n 中选择 k 个数满足前一个数能被后一个数整除 即bi+1 / bi = n (n >= 1),求这样的序列总共有多少个。因为数据可能会比较大,要对 1e9+7 取余。
思路:
从个位往最高位进行分析,可以发现:当 k = 1 (即序列只有1个整数) 的时候,num(序列个数) = n; 当 k = 2 时, 便于讨论,可以假设 n = 5, 因为后一个数是前一个数的整数倍,故应该从最后往前推,那么最后一位可以为 1, 2, 3, 4, 5 。 因为它后面没有数字,我们讨论 k - 1 位,在这里就是第一位,第一位(用 b1 表示)也可以是1, 2, 3, 4, 5 。当 b1 = 1 时, b2 = 1, 2, 3, 4, 5 ; 当 b1 = 2 时, b2 = 2, 4; 当 b1 = 3 时, b2 = 3;当 b1 = 4 时, b2 = 4; 当 b1 = 5 时, b2 = 5; 故 num = 5+2+1+1+1 = 10。 再序列再增加一位, k = 3 的时候, 当 b1 = 1 的时候, b2 = 1, 2, 3, 4, 5 ,情况同 k = 2, 故此时 num 个数为 10 ; 当 b1 = 2 时, b2 = 2, 4 ,相应的 b1 = 2, 4, 4 ,即当 b2 = 2 || 4 时候的和,同理 b1 = 3, 4, 5 。这是个递归的过程。
递归实现代码:
/* ***
* @Codeforce problem 414B. Mashmokh and ACM
* @author: ckmoonfish
* @Date:2014.4.11
* @combinatories, dp
******/
#include <stdio.h>
#define mod 1000000007
int num = 0;
void dps(int t, int k, int n){
int i = 0;
if(k == 0){
num = (num+1) % mod; // 表示创建完一个序列
//printf("i=%d, t=%d, k=%d, n=%d, num=%d\n", i, t, k, n, num);
}
else
for(i = t; i <= n; i += t){
//printf("%d ", i);
dps(i, k-1, n); // 从t,2*t,3*t <= n 一个个的找序列
}
}
int main(){
int j, n, k;
scanf("%d%d", &n, &k);
for(j = 1; j <= n; j++){ j 代表 序列中的第一个数
dps(j, k-1, n);
}
printf("%d\n", num);
return 0;
}
根本就没有题目标签的思想:DP 。交上去肯定就 TLE 了。
DP 思路: DP就是一个逆推的过程,用能简单求出的已知项向未知项推进,在推进的过程记录下求出的每一个状态的值,并在求未知项的过程中,只考虑前一步的值。
根据上面对 k = 1, 2, 3 的的分析知道: b1 = 1 时, numk3 = (b2= 1, 2, 3, 4, 5); b1 = 2 时, numk3 = (b2 = 2, 4);b1 = 3 时, numk3 = (b2 = 3; b1 = 4 时, numk3 = (b2 = 4);b1 = 5 时, numk3 = (b2 = 5);那么 k = 4 的时候呢? b1 = 1 时, numk4 = ( b2= 1, 2, 3, 4, 5 ) 。 同理可以推 k = 5, 6, ... 符合我们上面的 DP 思路。
可以写出 递推 公式: d[k-1][i] = d[k][i] + d[k][2*i] + d[k][3*i] + ... + d[k][p*i] ;其中 p*i <= n 。
代码:
/* ***
* @Codeforce problem 414B. Mashmokh and ACM
* @author: ckmoonfish
* @Date:2014.4.11
* @combinatories, dp
******/
#include <stdio.h>
#include <string.h>
#define MAXN 2014
#define mod 1000000007
int ins[MAXN][MAXN];
int main(){
int i, j, p, n, k, num, st[MAXN];
memset(ins, 0, sizeof(ins));
memset(st, 0, sizeof(st));
num = 0;
scanf("%d%d", &n, &k);
for(i = 1; i <= n; ++i)
st[i] = n / i;
for(i = 1; i <= n; i++)
ins[k][i] = 1;
for(i = k-1; i > 0; i--){
for(j = 1; j <= n; j++){
for(p = j; p <= n; p += j)
ins[i][j] = (ins[i][j] + ins[i+1][p]) % mod;
// printf("ins[%d][%d] = %d\n", i, j, ins[i][j]);
}
}
for(i = 1; i <= n; ++i){
num = (num + ins[1][i]) % mod;
}
printf("%d", num % mod);
return 0;
}
注意取模,当数据很大的时候,容易超范围。