网易2017——小易喜欢的数列

小易喜欢的数列

小易非常喜欢拥有以下性质的数列:
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范围内,并且满足第三条性质,所以小易是喜欢这个数列的
但是小易不喜欢{4,4,4,2}这个数列。小易给出n和k,希望你能帮他求出有多少个是他会喜欢的数列。 

输入描述:
输入包括两个整数n和k(1 ≤ n ≤ 10, 1 ≤ k ≤ 10^5)


输出描述:
输出一个整数,即满足要求的数列个数,因为答案可能很大,输出对1,000,000,007取模的结果。
输入例子1:
2 2
输出例子1:
3

思路:

动态规划,但要注意超时问题,因为k值可能很大。建立一个dp[n][k+1],用以保存计算过的数据,dp[i][j]表示第i位数字为j时,可能的数列情况,所以最后的返回值,应该是dp[n-1][1]+dp[n-1][2]+.....+dp[n-1][k]


会超时的方法:

public class wangyi0812_3 {
    static final int MOD = 1000000007;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int k = in.nextInt();
        int[][] dp = new int[n][k + 1];
        for (int i = 1; i < k + 1; i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < k + 1; j++) {
                for (int m = j + 1; m < k + 1; m++) {
                    if (m % j != 0) // 会对每一个m值都进行判定,当k很大时,复杂度很大
                        dp[i][j] = (dp[i][j] + dp[i - 1][m]) % MOD;
                }
                for (int m = j; m > 0; m--)
                    dp[i][j] = (dp[i][j] + dp[i - 1][m]) % MOD;
            }
        }
        int result = 0;
        for (int j = 1; j < k + 1; j++)
            result = (result + dp[n - 1][j]) % MOD;
        System.out.println(result);
    }

优化后:

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int k = in.nextInt();
        int[][] dp = new int[n][k + 1];
        for (int i = 1; i < k + 1; i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i < n; i++) {
            int sum = 0;
            for (int j = 1; j < k + 1; j++)
                sum = (sum + dp[i - 1][j]) % MOD; // 同一个i值的情况下,sum重复利用
            for (int j = 1; j < k+1; j++) {
                int p = 2;
                int invalid = 0;
                while (p * j <= k) { // 用乘法操作而不是之前的m取余,可以减少计算量
                    //计算不符合要求的数字和
                    invalid = (invalid + dp[i - 1][p * j]) % MOD; // 每个j的invalid值都不同
                    p++;
                }
                dp[i][j] = (sum - invalid + MOD) % MOD;
            }

            }
        int result = 0;
        for (int j = 1; j < k + 1; j++)
            result = (result + dp[n - 1][j]) % MOD;
        System.out.println(result);
        }

    }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值