小易非常喜欢拥有以下性质的数列:
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取模的结果。
2 2
3
public class Main { private static int ans = 0; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n, k; n = sc.nextInt(); k = sc.nextInt(); boolean[] visited = new boolean[n+1]; backtracking(new ArrayList<Integer>(), n, k); System.out.println(ans); } private static void backtracking(ArrayList<Integer> list, int n, int k){ if(n==0){ ans++; ans = ans % 1000000007; return; } for(int i = 1;i<=k;i++){ if(list.size()==0 || (list.size()!=0 && (list.get(list.size()-1)<=i || list.get(list.size()-1)%i!=0))) { list.add(i); backtracking(list, n - 1, k); list.remove(list.size()-1); } } } }
state[i][j]表示整个状态空间,其中i(1<=i<=n)表示数列的长度,j(1<=j<=k)表示数列长度为i且以数字j结尾。
递推关系有:state[i][j] += state[i-1][m] (1<=m<=k, 并且(m,j)是个合法的数列),但是直接按照递推关系,用三层for循环会超时。为此可以先将长度为i-1的合法数列求和(记为sum)。然后对于数列长度为i的每一个j,求出数列长度为i-1时非法的序列个数(记为invalid),即有state[i][j] = sum - invalid。
对于invalid求取,可以参照素数筛选。算法的时间复杂度大概为O(nkloglogk)
public class Main { static final int mod = 1000000007; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n, k; n = sc.nextInt(); k = sc.nextInt(); int[][] state = new int[n+1][k+1]; state[0][1] = 1; for(int i = 1;i<=n;i++){ for(int j=1;j<=k;j++){ for(int m=1;m<=k;m++){ if(m<=j || m%j!=0) state[i][j]+=state[i-1][m]; } } } int sum = 0; for(int i = 1;i<=k;i++){ sum = (sum+state[n][i])%mod; } System.out.println(sum); } }
public class Main { static final int mod = 1000000007; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n, k; n = sc.nextInt(); k = sc.nextInt(); int[][] state = new int[n+1][k+1]; state[0][1] = 1; for(int i = 1;i<=n;i++){ int sum = 0; for(int j = 1;j<=k;j++){ sum = (sum+state[i-1][j])%mod; } for(int j=1;j<=k;j++){ int invalid = 0; int p = 2; //满足的条件为: A<=B || A%B!=0 //则不满足的条件为: A>B && A%B==0 //此处即为 (p*j,j) while (p*j<=k){ invalid = (invalid+state[i-1][p*j])%mod; p++; } state[i][j] = (sum-invalid+mod)%mod; } } int sum = 0; for(int i = 1;i<=k;i++){ sum = (sum+state[n][i])%mod; } System.out.println(sum); } }
//用动态规划做,列出动态规划式子 import java.util.*; public class Main{ public static final int mod = 1000000007; public static void main(String[ ] args){ Scanner input = new Scanner(System.in); int n = input.nextInt(); int k = input.nextInt(); int[][] temp = new int[n+1][k+1]; /*[0 1 2 (k-1) k] 0 0 1 0 0 1 0 (n-1) n */ //动态规划,其中 invaild = temp[i-1][A] A即为满足A mod B ==0 //temp[i][j] = invalid-(temp[i-1][1] +.....+ temp[i-1][k]) int sum, invalid, z; temp[0][1] = 1; //使得n=1时,各k列能初始化为1 for(int i=1;i<=n;i++){ sum = 0; for(int j=1;j<=k;j++){ sum = (sum + temp[i-1][j]) % mod; } for(int j=1;j<=k;j++){ invalid = 0; z = 2; while(j*z<=k){ invalid = (invalid + temp[i-1][***od; z++; } temp[i][j] = (sum - invalid + mod) % mod; //防止为负数 } } sum = 0; for(int j=1;j<=k;j++){ sum = (sum + temp[n][j]) % mod; //最后的结果为最后一行所有可能的和 } System.out.println(sum); } }
import java.util.Scanner; public class Problem_201703 { private static final int MOD = 1000000007; public static void main(String[] args) { Scanner scan = new Scanner(System.in); while (scan.hasNext()) { int n = scan.nextInt(); int k = scan.nextInt(); //dp[i][j]表示长度为i的序列以j结束数字的数列个数 //dp[i][j] = dp[i - 1][m] (1 <= m <= k)并且(m,j)是一个有效的序列 int[][] dp = new int[n + 1][k + 1]; dp[0][1] = 1; for (int i = 1; i <= n; i++) { int sum = 0; //所有可能组合 for (int j = 1; j <= k; j++) { sum = (sum + dp[i - 1][j]) % MOD; } for (int j = 1; j <= k; j++) { //删除所有不满足条件的情况,类似素数筛选的过程 int invalid = 0; int p = 2; while (p * j <= k) { //dp[i - 1][p * j]违反了A % B != 0,因此剔除 invalid = (invalid + dp[i - 1][p * j]) % MOD; p++; } //为初始化添加增量 dp[i][j] = (sum - invalid + MOD) % MOD; } } int res = 0; for (int i = 1; i <= k; i++) { res = (res + dp[n][i]) % MOD; } System.out.println(res); } scan.close(); } }