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

来源:互联网 发布:java反射调用泛型方法 编辑:程序博客网 时间:2024/05/17 21:49

小易喜欢的数列

小易非常喜欢拥有以下性质的数列:
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);        }    }




原创粉丝点击