From 672c71d19fb2b721b4e72cb226bed92bb9ae8075 Mon Sep 17 00:00:00 2001 From: Departuers <2644631299@qq.com> Date: Mon, 3 Aug 2020 22:06:14 +0800 Subject: [PATCH] c --- ...\345\215\225\350\260\203\346\240\210.java" | 4 +- ...\346\220\254\345\257\235\345\256\244.java" | 62 ++++++++++++++ ...\344\270\262\345\210\267\345\255\220.java" | 43 ++++++++++ ...\345\233\236\346\226\207\344\270\262.java" | 74 ++++++++++++++++ ...\345\233\236\346\226\207\344\270\262.java" | 42 ++++++++++ ...\345\217\267\345\214\271\351\205\215.java" | 45 ++++++++++ ...\345\255\220\345\220\210\345\271\266.java" | 7 ++ .../Windy\346\225\260.java" | 64 +++++++++++++- .../\344\270\215\350\246\20162.java" | 69 +++++++++++++++ ...\347\232\204\346\225\260\351\207\217.java" | 21 +++-- .../\346\225\260\344\275\215dp.md" | 3 +- ...\345\222\214\344\275\231\346\225\260.java" | 84 +++++++++++++++++++ ...\345\255\227\346\270\270\346\210\217.java" | 22 +++-- .../LIS\346\250\241\345\236\213/LIS.java" | 1 + .../POJ3486\347\224\265\350\204\221.java" | 44 ++++++++-- ...\345\255\220\345\272\217\345\210\227.java" | 48 +---------- 16 files changed, 558 insertions(+), 75 deletions(-) create mode 100644 "ACWing/src/dp/\345\214\272\351\227\264dp/HDU1421\346\220\254\345\257\235\345\256\244.java" create mode 100644 "ACWing/src/dp/\345\214\272\351\227\264dp/HDU2476\345\255\227\347\254\246\344\270\262\345\210\267\345\255\220.java" create mode 100644 "ACWing/src/dp/\345\214\272\351\227\264dp/POJ1159\346\267\273\345\212\240\345\255\227\347\254\246\345\233\236\346\226\207\344\270\262.java" create mode 100644 "ACWing/src/dp/\345\214\272\351\227\264dp/UVA\345\210\240\351\231\244\345\233\236\346\226\207\344\270\262.java" create mode 100644 "ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" create mode 100644 "ACWing/src/dp/\346\225\260\344\275\215dp/\344\270\215\350\246\20162.java" create mode 100644 "ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\345\222\214\344\275\231\346\225\260.java" diff --git "a/ACWing/src/basic/stack/\345\215\225\350\260\203\346\240\210.java" "b/ACWing/src/basic/stack/\345\215\225\350\260\203\346\240\210.java" index b542230..9b4fb08 100644 --- "a/ACWing/src/basic/stack/\345\215\225\350\260\203\346\240\210.java" +++ "b/ACWing/src/basic/stack/\345\215\225\350\260\203\346\240\210.java" @@ -27,8 +27,8 @@ public class 单调栈 { x = sc.nextInt(); while (tt != 0 && stk[tt] >= x) tt--; //tt==0代表找不到比它小的数 - if (tt == 0) System.out.print(-1); - else System.out.println(stk[tt]); + if (tt == 0) System.out.print(-1+" "); + else System.out.print(stk[tt]+" "); stk[++tt] = x; //stk[0]这个位置什么都不存,到了这个位置代表找不到!!! } diff --git "a/ACWing/src/dp/\345\214\272\351\227\264dp/HDU1421\346\220\254\345\257\235\345\256\244.java" "b/ACWing/src/dp/\345\214\272\351\227\264dp/HDU1421\346\220\254\345\257\235\345\256\244.java" new file mode 100644 index 0000000..36ed5ec --- /dev/null +++ "b/ACWing/src/dp/\345\214\272\351\227\264dp/HDU1421\346\220\254\345\257\235\345\256\244.java" @@ -0,0 +1,62 @@ +package dp.区间dp; + +import java.util.Arrays; +import java.util.Scanner; + +/** + * https://blog.csdn.net/zhengde152/article/details/81428078 + * 有n个行李,每个行李有一个重量。 + * 现在你要搬走2k个行李,你一共去k次。每次左手右手各拿一个行李, + * 假设这两个行李的重量分别为x和y。 + * 那么这一次搬运产生的疲惫度是(x-y)^2 + * 现在你希望最小化疲惫度。 + * 2≤2k≤n<2000 + * Sample Input + * 2 1 1 3 + * Sample Output + * 4 + * n个物品选择2k个,分成k组,不好选 + * 假设拿到了2k个物品,如何组合使得疲劳度最小 + * 如果有4个行李,从小到大师a,b,c,d + * (a-b)^2+(c-d)^2 < (a-c)^2+(b-d)^2 + * 显然(a,b)(c,d)分组最优 + * 因此2k个行李从小到大排序一次取2个配对最好 + * 可以一开始就对n个物品排序 + * f[i,j]表示从前i个物品中选出了j对的最小疲惫度 + * 考虑last + * 考虑第i个取不取,如果取上第i个,一个和第i-1个配对 + * 因此要求前i-2个物品选出j-1对 + * f[i,j]=min{f[i,j],f[i-2][j-1]+a[i]-a[i-1]*a[i]-a[i-1]} + * 如果不取则f[i,j]=f[i-1,j] + */ +public class HDU1421搬寝室 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + while (true) { + if (!sc.hasNext()) break; + n = sc.nextInt(); + k = sc.nextInt(); + for (int i = 1; i <= n; i++) { + a[i] = sc.nextInt(); + } + Arrays.sort(a, 1, n + 1); + int t = Integer.MAX_VALUE / 2; + for (int i = 0; i <= n; i++) { + for (int j = 1; j <= k; j++) { + f[i][j] = t; + } + } + for (int i = 2; i <= n; i++) { + for (int j = 1; j * 2 <= i; j++) { + f[i][j] = Math.min(f[i - 2][j - 1] + (a[i] - a[i - 1]) * (a[i] - a[i - 1]), f[i - 1][j]); + } + } + System.out.println(f[n][k]); + } + + } + + static int[] a = new int[2010]; + static int[][] f = new int[2010][2010]; + static int n, k; +} diff --git "a/ACWing/src/dp/\345\214\272\351\227\264dp/HDU2476\345\255\227\347\254\246\344\270\262\345\210\267\345\255\220.java" "b/ACWing/src/dp/\345\214\272\351\227\264dp/HDU2476\345\255\227\347\254\246\344\270\262\345\210\267\345\255\220.java" new file mode 100644 index 0000000..e8aa90a --- /dev/null +++ "b/ACWing/src/dp/\345\214\272\351\227\264dp/HDU2476\345\255\227\347\254\246\344\270\262\345\210\267\345\255\220.java" @@ -0,0 +1,43 @@ +package dp.区间dp; + +import java.util.Scanner; + +/** + * f[i,j]表示从A到B的最小步数,不方便转移 + * 用g[i,j]表示i~j从空串变成B的最小步数, + * 然后确定哪些部分保留原来的A,哪些部分重新刷 + * 考虑s[i]==s[j] s[i]=s[i+1] s[j]=s[j-1],分2种情况 + * 在g[i,j]=min{ g[i,j],g[i+1,j] } 染i~j或者i+1~j的时候顺便染 + * 否则g[i,j]=min{ g[i,j],g[i+1,j]+1} + */ +public class HDU2476字符串刷子 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + for (int i = 1; i <= n; i++) { + g[i][i] = 1; + } + for (int len = 1; len <= n; len++) { + for (int l = 1; l + len - 1 <= n; l++) { + int r = l + len - 1; + g[l][r] = (int) 1e9; + if (s[l] != s[l + 1] && s[l] != s[r]) { + g[l][r] = Math.min(g[l][r], g[l + 1][r] + 1); + } else { + g[l][r] = Math.min(g[l][r], g[l + 1][r]); + } + if (s[r - 1] != s[r] && s[r] != s[l]) { + g[l][r] = Math.min(g[l][r], g[l][r - 1] + 1); + } else g[l][r] = Math.min(g[l][r], g[l][r - 1]); + for (int k = l; k < r; k++) { + g[l][r] = Math.min(g[l][k] + g[k + 1][r], g[l][r]); + } + } + } + } + + static char[] s; + static int n; + static int[][] g = new int[110][110]; + static int[][] f = new int[110][110]; + +} \ No newline at end of file diff --git "a/ACWing/src/dp/\345\214\272\351\227\264dp/POJ1159\346\267\273\345\212\240\345\255\227\347\254\246\345\233\236\346\226\207\344\270\262.java" "b/ACWing/src/dp/\345\214\272\351\227\264dp/POJ1159\346\267\273\345\212\240\345\255\227\347\254\246\345\233\236\346\226\207\344\270\262.java" new file mode 100644 index 0000000..e081599 --- /dev/null +++ "b/ACWing/src/dp/\345\214\272\351\227\264dp/POJ1159\346\267\273\345\212\240\345\255\227\347\254\246\345\233\236\346\226\207\344\270\262.java" @@ -0,0 +1,74 @@ +package dp.区间dp; + +import java.io.*; +import java.util.StringTokenizer; + +import static java.lang.System.in; + +/** + * 给定一个字符串,问最少加几个字符可以使它变为回文串。 + * 比如Ab3bd,添加两个字符后可以变成dAb3bAd或Adb3bdA。 + * 显然这是最优方案。 + * 字符串长度≤5000 + * f[i,j]表示Si~Sj(也就是字符串范围)至少要插入的字符数量, + * 转移方程: + * 如果S[i]==S[j]也就是该区间头尾相等,,则有f[i,j]=f[i+1,j-1] + * 若头尾不相等则f[i,j]=min( f[i,j-1] ,f[i+1,j] )+1 + * 头尾不相等有两种方法更新:从头部插,还是从尾部插,使得对称 + * 因为S[i]不等于S[j]考虑i~j-1范围内的最小添加已经求出 + * 则 s[j] i....j-1 s[j] 拼接一个字符串到最前面使得对称 + * 则 i i+1....j s[i] 拼接一个字符串到最后面使得对称 + * Sample Input + * 5 + * Ab3bd + * Sample Output + * 2 + */ +public class POJ1159添加字符回文串 { + public static void main(String[] args) throws IOException { + n = nextInt(); + char[] t = next().toCharArray(); + //只能倒着枚举 + for (int i = n - 1; i >= 0; i--) { + for (int j = i; j < n; j++) { + if (i == j) continue; + //在计算f[i,j]时,f[i+1][j-1]已经算好了 + //i是由i+1更新的所以从大到小,而j是通过j-1更新的要从小到大 + if (t[i] == t[j]) { + f[i][j] = f[i + 1][j - 1]; + } else { + f[i][j] = Math.min(f[i][j - 1], f[i + 1][j]) + 1; + } + } + } + bw.write(f[0][n - 1] + " "); + bw.flush(); + } + + static int n, m; + // static char[] s = new char[5001]; + static int[][] f = new int[5010][5010]; + static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out)); + static BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + static StringTokenizer tokenizer = new StringTokenizer(""); + + static String nextLine() throws IOException {// 读取下一行字符串 + return reader.readLine(); + } + + static String next() throws IOException {// 读取下一个字符串 + while (!tokenizer.hasMoreTokens()) { + //如果没有字符了,就是下一个,使用空格拆分, + tokenizer = new StringTokenizer(reader.readLine()); + } + return tokenizer.nextToken(); + } + + static int nextInt() throws IOException {// 读取下一个int型数值 + return Integer.parseInt(next()); + } + + static double nextDouble() throws IOException {// 读取下一个double型数值 + return Double.parseDouble(next()); + } +} diff --git "a/ACWing/src/dp/\345\214\272\351\227\264dp/UVA\345\210\240\351\231\244\345\233\236\346\226\207\344\270\262.java" "b/ACWing/src/dp/\345\214\272\351\227\264dp/UVA\345\210\240\351\231\244\345\233\236\346\226\207\344\270\262.java" new file mode 100644 index 0000000..fae6b92 --- /dev/null +++ "b/ACWing/src/dp/\345\214\272\351\227\264dp/UVA\345\210\240\351\231\244\345\233\236\346\226\207\344\270\262.java" @@ -0,0 +1,42 @@ +package dp.区间dp; + +import java.util.Arrays; +import java.util.Scanner; + +/** + * 给定一个字符串,问有几种删字符的方案使得它变为回文串。 + * 可以删掉B、BA、 AB、两个A、不删。5种 + * 字符串长度≤5000 + * 实际上统计该串有多少个回文子序列 + * f[i,j]表示Si~Sj范围内的回文串个数 + * 转移考虑last + * S[i]==S[j]那么要统计f[i+1][j]和f[i][j-1] + * 虽然会把f[i+1,j-1]统计两次, + * 但是f[i+1,j-1]中的回文串可以加上S[i]和S[j]再形成f[i+1][j-1]个回文串 + * f[i,j]=f[i+1,j]+f[i,j-1]+1 + */ +public class UVA删除回文串 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + s = sc.next().toCharArray(); + n = s.length; + for (int i = 0; i < f.length; i++) { + Arrays.fill(f[i], -1); + } + System.out.println(dp(0, n - 1)); + System.out.println(f[0][n - 1]); + } + + static int dp(int l, int r) { + if (l == r) return 1; + if (l > r) return 0; + if (f[l][r] != -1) return f[l][r]; + if (s[l] == s[r]) return f[l][r] = dp(l, r - 1) + dp(l + 1, r) + 1; + else return f[l][r] = dp(l, r - 1) + dp(l + 1, r) - dp(l + 1, r - 1); + } + + static int n; + static char[] s; + static int[][] f = new int[5100][5010]; +} diff --git "a/ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" "b/ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" new file mode 100644 index 0000000..dfa8ce3 --- /dev/null +++ "b/ACWing/src/dp/\345\214\272\351\227\264dp/\346\213\254\345\217\267\345\214\271\351\205\215.java" @@ -0,0 +1,45 @@ +package dp.区间dp; + +import java.util.Scanner; + +/** + * 给出一个只有() []四种字符组成的字符串,取出一个最长的子序列使得他们满足括号匹配。 + * 样例: + * ([]]) (答案: 4)取出来([]) + * ([][][) (答案: 6) 取出来([][]) + * f[i,j]表示[i,j]区间中的最长子序列 + * 如果S[i]和S[j]可以匹配那么f[i,j]=f[i+1][j-1]+2 + * 显然上述,也就是i+1~j-1这个小区间最长匹配+2 + * 如果S[i]和S[j]不能匹配 + * 那么i~j的答案也可以由两个子区间的答案合并而来 + * f[i,j]=max(f[i,j] , f[i,k]+f[k+1,j]) + * 如([])([])从中间分界线,那么它们依然可以匹配,符合要求 + * O(n^3) + */ +public class 括号匹配 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + char[] t = sc.next().toCharArray(); + for (int i = 0; i < t.length; i++) { + s[i + 1] = t[i]; + } + int n = t.length; + for (int len = 2; len <= n; len++) { + for (int l = 1; l + len - 1 <= n; l++) { + int r = l + len - 1; + if ((s[l] == '(' && s[r] == ')') || s[l] == '[' && s[r] == ']') { + f[l][r] = f[l + 1][r - 1] + 2; + }//查看头尾是否匹配 + + //枚举小区间,推出大区间最长序列 + for (int k = l; k < r; k++) { + f[l][r] = Math.max(f[l][k] + f[k + 1][r], f[l][r]); + } + } + } + System.out.println(f[1][n]); + } + + static char[] s = new char[1000]; + static int[][] f = new int[2000][2000]; +} diff --git "a/ACWing/src/dp/\345\214\272\351\227\264dp/\347\237\263\345\255\220\345\220\210\345\271\266.java" "b/ACWing/src/dp/\345\214\272\351\227\264dp/\347\237\263\345\255\220\345\220\210\345\271\266.java" index c52ead1..ba02c76 100644 --- "a/ACWing/src/dp/\345\214\272\351\227\264dp/\347\237\263\345\255\220\345\220\210\345\271\266.java" +++ "b/ACWing/src/dp/\345\214\272\351\227\264dp/\347\237\263\345\255\220\345\220\210\345\271\266.java" @@ -37,6 +37,13 @@ import java.util.Scanner; * i~k合并的最小代价结合状态定义恰好是f[i,k] * k+1,j合并的最小代价结合状态定义恰好是f[k+1,j] * 最后加上他们的和 即可:s[j]-s[i-1] + * + * 顾名思义,区间dp就是区间上的dp, + * 通过先算出小区间的dp的到最优解,再去得到大区间的最优解 + * 一般设f[i,j]为区间[i,j]的最优解,一般f[i,j]都可以由[i,j]的子区间更新得到 + * 该题合并之前是两堆,合并之后是一堆,可以枚举分界线 + * f[i,j]=min{ f[i,k]+f[k+1,j]+a[j]-a[i-1] | i<=k=2 + * 假设第2位填k,组成不降数,那么变成最高位为k,且只用填i-1位,为f[i-1,k] + * f[i,j]=f[i-1,k] k的取为0~9且|j-k|>=2求和,值 + */ + private static void init() { + for (int i = 0; i <= 9; i++) { + f[1][i] = 1; + } + for (int i = 2; i < N; i++) {//从数字位数为2开始枚举 + for (int j = 0; j <= 9; j++) { + for (int k = 0; k <= 9; k++) {//0~9可选,但满足绝对值之差大于等于2 + if (Math.abs(j - k) >= 2) f[i][j] += f[i - 1][k]; + } + } + } } -} + + static int dp(int n) { + if (n == 0) return 0;//0不是windy数 + ArrayList num = new ArrayList(); + while (n != 0) { + num.add(n % 10); + n /= 10; + } + int res = 0, last = -2;//last要与0~9都满足相差大于等于-2,可选范围为last<=-2 last>=11 + for (int i = num.size() - 1; i >= 0; i--) { + int x = num.get(i); + for (int j = i == num.size() - 1 ? 1 : 0; j < x; j++) {//如果是第一位,从1开始枚举否则从0开始 + if (Math.abs(j - last) >= 2) { + res += f[i + 1][j]; + } + } + if (Math.abs(x - last) >= 2) last = x; + else break; + if (i == 0) res++;//走到了最后 + } + //枚举有前导0的数 + for (int i = 1; i < num.size(); i++) { + for (int j = 1; j <= 9; j++) { + res += f[i][j]; + } + } + return res; + } + + static int A, B, N = 11; + static int[][] f = new int[N][10]; +} \ No newline at end of file diff --git "a/ACWing/src/dp/\346\225\260\344\275\215dp/\344\270\215\350\246\20162.java" "b/ACWing/src/dp/\346\225\260\344\275\215dp/\344\270\215\350\246\20162.java" new file mode 100644 index 0000000..1866ed0 --- /dev/null +++ "b/ACWing/src/dp/\346\225\260\344\275\215dp/\344\270\215\350\246\20162.java" @@ -0,0 +1,69 @@ +package dp.数位dp; + +import java.util.ArrayList; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_30277239/article/details/104502932 + */ +public class 不要62 { + public static void main(String[] args) { + init(); + Scanner sc = new Scanner(System.in); + l = sc.nextInt(); + r = sc.nextInt(); + System.out.println(dp(r) - dp(l - 1)); + + } + + static int l, r, N = 9; + static int[][] f = new int[N][10]; + + + /** + * 树的左侧分支用dp预处理 + * f[i,j]表示最高位是j,只有一共有i位的不降数的集合 + * 属性;count,计数 + * 状态计算划分,f[i,j] + * 考虑last,找到一个分界线, + * j _ _ _ _... 第一位填j,第二位可以选填j,j+1,j+2...9 + * 假设第2位填k,组成不降数,那么变成最高位为k,且只用填i-1位,为f[i-1,k] + * f[i,j]=f[i-1,k] k的取为j<=k<=9求和,值 + */ + static void init() { + for (int i = 0; i <= 9; i++) { + if (i != 4) + f[1][i] = 1; + } + for (int i = 2; i < N; i++) { + for (int j = 0; j <= 9; j++) { + if (j != 4) + for (int k = 0; k <= 9; k++) { + if (k == 4 || j == 6 && k == 2) continue; + f[i][j] += f[i - 1][k]; + } + } + } + } + + static int dp(int n) { + if (n == 0) return 1; + ArrayList num = new ArrayList(); + while (n != 0) { + num.add(n % 10); + n /= 10; + } + int res = 0, last = 0; + for (int i = num.size() - 1; i >= 0; i--) { + int x = num.get(i); + for (int j = 0; j < x; j++) { + if (j == 4 || last == 6 && j == 2) continue; + res += f[i + 1][j]; + } + if (x == 4 || last == 6 && x == 2) break; + last = x; + if (i == 0) res++; + } + return res; + } +} diff --git "a/ACWing/src/dp/\346\225\260\344\275\215dp/\345\272\246\347\232\204\346\225\260\351\207\217.java" "b/ACWing/src/dp/\346\225\260\344\275\215dp/\345\272\246\347\232\204\346\225\260\351\207\217.java" index 20aff6a..3e502e7 100644 --- "a/ACWing/src/dp/\346\225\260\344\275\215dp/\345\272\246\347\232\204\346\225\260\351\207\217.java" +++ "b/ACWing/src/dp/\346\225\260\344\275\215dp/\345\272\246\347\232\204\346\225\260\351\207\217.java" @@ -4,8 +4,11 @@ import java.util.ArrayList; import java.util.Scanner; /** + * https://blog.csdn.net/qq_30277239/article/details/104468664 * 489199 894799999 15 3 + * out 3876 * 15 20 2 2 + * out 3 */ public class 度的数量 { public static void main(String[] args) { @@ -23,26 +26,26 @@ public class 度的数量 { static int dp(int n) { if (n == 0) return 0; ArrayList num = new ArrayList(); - //把数字转换成B进制 + //把数字转换成B进制,每一位都填上有且只有K个1,其余全是0 while (n != 0) { num.add(n % B); n /= B; } - System.out.println(num); - int res = 0, last = 0; + int res = 0, last = 0;//这里last存的是前面有多少个1,含义不同题目不一样 for (int i = num.size() - 1; i >= 0; i--) { int x = num.get(i); - if (x != 0) { - res += f[i][K - last]; - if (x > 1) { - if (K - last - 1 >= 0) res += f[i][K - last - 1]; + //每一位只能填0或者1 + if (x != 0) {//求左边分支,如果这一位能填 + res += f[i][K - last];//这一位填0能够成的 + if (x > 1) {//这一位如果填上给的数本身,大于1,分支不合法可以break + if (K - last - 1 >= 0) res += f[i][K - last - 1];//这一位填1 break; - }else { + } else { last++; if (last > K) break; } } - if (i == 0 && last == K) res++; + if (i == 0 && last == K) res++;//最右侧分支的方案 } return res; } diff --git "a/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\344\275\215dp.md" "b/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\344\275\215dp.md" index af806a8..4b08f4e 100644 --- "a/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\344\275\215dp.md" +++ "b/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\344\275\215dp.md" @@ -1,4 +1,4 @@ -###dp.数位dp +###dp.[数位dp](https://www.bilibili.com/video/BV1yT4y1u7jW) ```` 某一个区间[x,y]里,符合某种条件(满足某种性质)的数一共有多少个 @@ -10,3 +10,4 @@ 技巧2: 使用树的角度来考虑 +左边分支可以预处理,右边最终就是这个数本身 diff --git "a/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\345\222\214\344\275\231\346\225\260.java" "b/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\345\222\214\344\275\231\346\225\260.java" new file mode 100644 index 0000000..828d04b --- /dev/null +++ "b/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\345\222\214\344\275\231\346\225\260.java" @@ -0,0 +1,84 @@ +package dp.数位dp; + +import java.util.ArrayList; +import java.util.Scanner; + +/** + * https://blog.csdn.net/qq_30277239/article/details/104501801 + * 由于科协里最近真的很流行数字游戏。 + * 某人又命名了一种取模数,这种数字必须满足各位数字之和 mod N为 0。 + * 现在大家又要玩游戏了,指定一个整数闭区间 [a.b],问这个区间内有多少个取模数。 + * 输入格式 + * 输入包含多组测试数据,每组数据占一行。 + * 每组数据包含三个整数 a,b,N。 + * 输出格式 + * 对于每个测试数据输出一行结果,表示区间内各位数字和 mod N为 0 的数的个数。 + * 数据范围 + * 1≤a,b≤2^31−1, + * 1≤N<100 + * 输入样例: + * 1 19 9 + * 输出样例: + * 2 + */ +public class 数字和余数 { + static int l, r, N = 11, M = 110, P = 1; + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + l = sc.nextInt(); + r = sc.nextInt(); + P = sc.nextInt(); + init(); + System.out.println(dp(r) - dp(l - 1)); + } + + /** + * 假如第一位已经确定,第二位枚举x,后面的数随便填 + * {A(n-2)+x+(...)}mod N=0 + * 剩下的n-2位所有位数之和=(-A(n-2)-x)mod N + * f[i,j,k]表示,i位数字,且最高位为j,余数为k的所有集合 + * 考虑last,x____假如第二位填k 0<=x<=9 + * 各位数字之和 + * f[i,j,k]=f[i-1,x,(k-j)mod N] + */ + private static void init() { + for (int i = 0; i <= 9; i++) { + f[1][i][i % P]++; + } + for (int i = 2; i < N; i++) { + for (int j = 0; j <= 9; j++) { + for (int k = 0; k < P; k++) { + for (int x = 0; x <= 9; x++) { + f[i][j][k] += f[i - 1][x][mod(k - j, P)]; + } + } + } + } + } + + static int dp(int n) { + if (n == 0) return 1; + ArrayList num = new ArrayList(); + while (n != 0) { + num.add(n % 10); + n /= 10; + } + int res = 0, last = 0; + for (int i = num.size() - 1; i >= 0; i--) { + int x = num.get(i); + for (int j = 0; j < x; j++) { + res += f[i + 1][j][mod(-last, P)]; + } + last += x; + if (i == 0 && last % P == 0) res++; + } + return res; + } + + static int[][][] f = new int[N][10][M]; + + static int mod(int x, int y) { + return (x % y + y) % y; + } +} diff --git "a/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\346\270\270\346\210\217.java" "b/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\346\270\270\346\210\217.java" index 77ace25..e6bf722 100644 --- "a/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\346\270\270\346\210\217.java" +++ "b/ACWing/src/dp/\346\225\260\344\275\215dp/\346\225\260\345\255\227\346\270\270\346\210\217.java" @@ -35,6 +35,16 @@ public class 数字游戏 { static int N = 12; static int[][] f = new int[N][N]; + /** + * 树的左侧分支用dp预处理 + * f[i,j]表示最高位是j,只有一共有i位的不降数的集合 + * 属性;count,计数 + * 状态计算划分,f[i,j] + * 考虑last,找到一个分界线, + * j _ _ _ _... 第一位填j,第二位可以选填j,j+1,j+2...9 + * 假设第2位填k,组成不降数,那么变成最高位为k,且只用填i-1位,为f[i-1,k] + * f[i,j]=f[i-1,k] k的取为j<=k<=9求和,值 + */ static void init() { for (int i = 0; i <= 9; i++) { f[1][i] = 1; @@ -49,20 +59,22 @@ public class 数字游戏 { } static int get(int n) { - if (n < 10) return n + 1; + if (n == 0) return 1;//如果n=0那么while不会执行导致错误 ArrayList num = new ArrayList(); while (n != 0) {//取出n的每一位 num.add(n % 10); n /= 10; } - int res = 0, last = 0; + int res = 0, last = 0;//每一个数字比上一个数字大即可,存的就是上一个数字的值, + // last初始化为0,是因为第一位0~9都可以选,满足不降条件 for (int i = num.size() - 1; i >= 0; i--) { int x = num.get(i); - for (int j = last; j < x; j++) { - res += f[i + 1][j]; + for (int j = last; j < x; j++) {//枚举,last<=j + * 3 + * 3 + * 5 7 50 + * 6 8 + * 10 + * Sample Output + *

+ * 19 + */ public class POJ3486电脑 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); - n = sc.nextInt(); - c = sc.nextInt(); - - for (int i = 1; i <= n; i++) { - for (int j = i; j <= n; j++) { - m[i][j] = sc.nextInt(); + while (sc.hasNext()) { + n = sc.nextInt(); + c = sc.nextInt(); + for (int i = 1; i <= n; i++) { + for (int j = i; j <= n; j++) { + m[i][j] = sc.nextInt(); + } } + get(); } + } + + static void get() { + Arrays.fill(f, Integer.MAX_VALUE / 2); f[0] = 0; - f[1] = m[1][1] + c; - for (int i = 2; i <= n; i++) { +// f[1] = m[1][1] + c; + for (int i = 1; i <= n; i++) { for (int j = 1; j <= i; j++) { f[i] = Math.min(f[i], f[j - 1] + m[j][i] + c); } - System.out.println(f[i]); } System.out.println(f[n]); } diff --git "a/LeetCode/src/_152\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\345\272\217\345\210\227.java" "b/LeetCode/src/_152\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\345\272\217\345\210\227.java" index 970eaf7..a46e6bf 100644 --- "a/LeetCode/src/_152\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\345\272\217\345\210\227.java" +++ "b/LeetCode/src/_152\344\271\230\347\247\257\346\234\200\345\244\247\345\255\220\345\272\217\345\210\227.java" @@ -1,54 +1,8 @@ -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; - /** * */ public class _152乘积最大子序列 { - public static void main(String[] args) throws ScriptException { - dfs(0, 0, ""); - System.out.println(Calculation("1+3")); - } - - - static void dfs(int s, int state, String g) throws ScriptException { - if (s == 9) { - if (Calculation(g) == 1) { - System.out.println(g + "=1"); - } - return; - } - for (int i = 0; i <= 9; i++) { - if (((state >> i) & 1) != 1) { - state += 1 << i; - for (int j = 0; j < 4; j++) { - if (s == 8) { - String t = g; - dfs(s + 1, state, g + i); - g = t; - } else { - String t = g; - dfs(s + 1, state, g + i + op[j]); - g = t; - } - } - } - } - } - - static char[] op = {'+', '-', '*', '/'}; + public static void main(String[] args) { - public static Double Calculation(String formula) { - Double result = null; //计算结果 - ScriptEngineManager manager = new ScriptEngineManager(); //创建一个ScriptEngineManager对象 - ScriptEngine engine = manager.getEngineByName("js"); //通过ScriptEngineManager获得ScriptEngine对象 - try { - result = (Double) engine.eval(formula); //用ScriptEngine的eval方法执行脚本 - } catch (ScriptException e) { - result = Double.NaN; - return result; - } - return result; } } -- GitLab