小易喜欢的数列

题目:

小易喜欢的数列有以下性质的数列

(1)数列的长度为n。

(2)数列中的每个数都在1到k之间(包括1和k)。

(3)对于位置相邻的两个数A和B(A在B前),都满足A<=B或A MOD B != 0(满足其一即可)。

例如,n=4,k=7,那么{1,7,7,2},它的长度是4,所有数字也在1到7的范围内,并且满足性质(3),所以小易是喜欢这个数列的。但是小易不喜欢{4,4,4,2}这个数列。小易给出n和k,希望你能帮他求出有多少个是他喜欢的数列。

输入格式:
输入包括两个整数n和k(1<=n<=10,1<=k<=10000)。

输出格式:
输出一个整数,即满足要求的数列个数,因为答案可能很大,输出对1 000 000 007取模的结果。

1)问题分析

        这个问题要求计算满足特定条件的数列数量,其中数列长度为n,每个元素都在1到k之间。关键是理解并处理相邻元素之间的约束条件。

2)算法设计

  1. 先定义 dp[i][j] 用于表示长度为i且最后一个元素为j的数列的可能数目。
  2. 对长度为1的数列,每个可能的元素(1到k)都是有效的,所以初始状态dp[1][j] = 1。
  3. 对长度为i的数列,其最后一个元素为j时,可以通过遍历所有可能的前一个元素x(1到k),并检查 x 和 j 是否满足条件,累加所有可能的前缀组合数。
  4. 最后,所有可能的数列的数目是所有dp[n][j]的总和,其中j从1到k。

3) 伪代码

算法:计算满足条件的数列个数
输入:整数n和k
输出:满足条件的数列个数(mod 10^9+7)

1. 初始化 dp[1...k] 为 1  // 长度为1时,每种数列有且仅有一个
2. 对于 i = 2 到 n:
    2.1 初始化 new_dp[1...k] 为 0
    2.2 对于 j = 1 到 k:
        2.2.1 对于 x = 1 到 k:
            2.2.2 如果 x ≤ j 或者 x % j ≠ 0:
                2.2.3 new_dp[j] += dp[x]
                2.2.4 new_dp[j] %= MOD
    2.3 dp = new_dp  // 更新dp数组
3. 计算总和 sum(dp[1...k])
4. 返回 sum

4)算法思维导图

5) 算法时间复杂度分析

外层循环n次,中层循环n次,内层循环n次,且每次操作都是常数时间。因此,时间复杂度为O(n3)

6)输出结果

7) 实验心得

       通过这次实验,我深刻理解了动态规划在组合计数问题中的应用。本题的关键在于正确地定义状态以及状态转移方程,并且需要注意模运算的时机以避免溢出。这道题也让我认识到在面对大数据规模时算法效率的重要性。虽然本题的直接动态规划解法在给定的约束下是可行的,但它提示我们在遇到类似问题时应该思考是否有更优的解决方案。

8)  完整代码

#include <stdio.h>
#include <string.h>

#define MOD 1000000007

int dp[11][10001];

int isValid(int A, int B) {
    return A <= B || A % B != 0;
}

int main() {
    int n, k;
    scanf("%d %d", &n, &k);

    memset(dp, 0, sizeof(dp));
    for (int j = 1; j <= k; j++) {
        dp[1][j] = 1;
    }

    for (int i = 2; i <= n; i++) {
        for (int j = 1; j <= k; j++) {
            for (int x = 1; x <= k; x++) {
                if (isValid(x, j)) {
                    dp[i][j] = (dp[i][j] + dp[i - 1][x]) % MOD;
                }
            }
        }
    }

    int result = 0;
    for (int j = 1; j <= k; j++) {
        result = (result + dp[n][j]) % MOD;
    }

    printf("%d\n", result);
    return 0;
}

数列与编程紧密相关,编程为数列的研究和应用提供了强大的工具,而数列问题为编程提供了丰富的实践场景。 在编程中实现数列计算是常见实践,以斐波那契数列为例,其本质是一个数字等于它前面两项的和,如 2 = 1 + 1,3 = 1 + 2,5 = 2 + 3 等[^2]。可以使用Java递归函数实现其第n项的计算: ```java package com.pnft.fibonacci; public class Fibonacci{ static int calculateFibonacci(int n) { if(n < 3) { return 1; } else { return calculateFibonacci(n-1) + calculateFibonacci(n-2); } } public static void main(String[] args) { System.out.println(calculateFibonacci(30)); } } ``` 上述代码通过递归的方式,根据斐波那契数列的定义计算出第30项的值为832040[^2]。 在处理数列求和问题时,也可以借助编程实现。例如求`1/1+2/1+3/2+5/3+8/5+13/8...`一直到n项的值。通过分析发现后一项的分子等于前一项的分母、分子之和,分母等于前一项的分子,使用C语言实现的代码如下: ```c int k,n; float num =0; //分子、分母 double i = 1,j = 1; double temp; printf("请输入所要求的项数:"); scanf("%d",&n); for(k = 1;k<= n;k++) { num += i / j; temp = i; i =i + j; j =temp; } //保留三位小数 printf("%.3lf",num); system("pause"); return 0; ``` 这段代码利用循环结构,根据总结出的数列规律完成了求和计算[^5]。 此外,编程还可解决与数列性质相关的问题。如小喜欢数列问题,要求数列满足特定性质,可使用动态规划算法来解决此类计数问题,输入数列长度n和取值范围k,输出满足条件的数列个数对`1000000007`取模的结果[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值