2.7
P1874 快速求和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
- 本题\(dp[i][j]\)代表以i结束和为k的最小加号用量,用\(num[i][j]\)代表i-j范围内的数字
- 转移方程为\(dp[i][k] = min(dp[j][k - num[j + 1][i]]) + 1\),该方程的意义为再以i结尾和为k的所用加号为,以j结尾和为k减去\([j + 1, i]形成的数字\)
- 于是我们可以考虑到需要遍历三个要素,i所有数字(字符串长度),k所有和(所给n),j(小于i),复杂度为\(O(len(s)^2 * n)\),大概是\(10^8\),需要考虑优化一下
- 考虑只要是\(num[j + 1][i] > n\)就不进入,那么理想的话可以降为\(10^7到10^8\),来一发看看情况,ok过了,感觉数据给的easy了点
- 注意初始化\(dp[0][0] = -1\),方便后面枚举到\(dp[i][num[i][i]] = 0\)这种情况
import java.io.*;
import java.util.*;
public class Main implements Runnable {
// static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
static Scanner cin = new Scanner(System.in);
static String s = new String();
static long n;
static final int N = 45;
static final int M = (int) (1e5 + 10);
static long[][] num = new long[N][N];//num[i][j] i-j的数字
static long[][] dp = new long[N][M];// dp[i][k] 以i结束和为j的最小加号用量
public static void main(String[] args) {
new Thread(null, new Main(), "", 1 << 29).start();
}
// public static int nextInt() throws IOException {
// cin.nextToken();
// return (int) cin.nval;
// }
@Override
public void run() {
s = cin.next();
n = cin.nextInt();
for (int i = 0; i <= 40; i++) Arrays.fill(dp[i], 0x3f3f3f3f);
for(int i = 1; i <= s.length(); i++) {
for (int j = i; j <= s.length(); j++) {
num[i][j] = num[i][j - 1] * 10 + (s.charAt(j - 1) - '0');
}
}
dp[0][0] = -1;
for (int i = 1; i <= s.length(); i++) {
for (int k = 0; k <= n; k++) {
for (int j = i - 1; j >= 0 && num[j + 1][i] <= n; j--) {
if (k - num[j + 1][i] < 0) continue;
dp[i][k] = Math.min(dp[i][k], dp[j][(int) (k - num[j + 1][i])] + 1);
}
}
}
long ans = 0x3f3f3f3f;
if (dp[s.length()][(int) n] < 45) {
ans = dp[s.length()][(int) n];
} else {
ans = -1;
}
cout.println(ans);
cout.flush();
}
}
P2758 编辑距离 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
- 考虑\(dp[i][j]\)代表以i的串变为以j结尾的串所需要的最少操作次数。那么一共有四种可能的转移
- 当\(a[i] == b[j]时,dp[i][j] = dp[i - 1][j - 1]\),因为不需要操作
- 当\(a[i] != b[j]时,dp[i][j] = min(dp[i - 1][j], dp[i][j - 1],dp[i - 1][j - 1]) + 1\),分别对应当子串1先去除末尾字符再转为j的操作数,子串1转为j-1子串再添加一个末尾字符,子串i-1变为j-1最后一个字符由修改操作变为j的末尾字符。
- 注意初始化即可
import java.io.*;
import java.util.*;
public class Main implements Runnable {
// static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
static Scanner cin = new Scanner(System.in);
static String s1, s2;
static final int N = (int) (2e3 + 10);
static long[][] dp = new long[N][N];
public static void main(String[] args) {
new Thread(null, new Main(), "", 1 << 29).start();
}
// public static int nextInt() throws IOException {
// cin.nextToken();
// return (int) cin.nval;
// }
@Override
public void run() {
s1 = cin.next();s2 = cin.next();
for (int i = 1; i<=s1.length(); i++) dp[i][0] = i;
for (int i = 1; i<=s2.length(); i++) dp[0][i] = i;
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i][j - 1], Math.min(dp[i - 1][j], dp[i - 1][j - 1])) + 1;
}
}
}
cout.println(dp[s1.length()][s2.length()]);
cout.flush();
}
}
P1439 【模板】最长公共子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
- 传统的做法是\(dp[i][j]\)定义为i,j结尾的两个序列中最长公共子序列的长度,转移方程可以考虑到为,\(当a[i] = b[j]时,dp[i][j] = dp[i - 1][j - 1] + 1 与 a[i] != b[j] 时,dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])\),这无疑我们要枚举i,j,也就是\(O(n^2)\)
- 然而题目给的\(n <= 10^5\), 我们考虑复杂度降为\(O(nlogn)\)的方法
- 举个例子 样例中3 2 1 4 5与1 2 3 4 5,我们把串1的序号也排出来\(3(1),2(2),1(3),4(4),5(5)\),可以发现他们的序号是递增的,那么我们的串1可以看作永远是递增的,那么串2就可以发现为\(1(3), 2(2),3(1),4(4),5(5)\),我们发现如果我们能找到序号递增的子序列那么他们一定是串1的子序列。
- 那么问题就转换成了求单序列的最长递增子序列,用个二分优化一下即可。
import java.io.*;
import java.util.*;
public class Main implements Runnable {
static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
static int n;
static final int N = (int) (1e5 + 10);
static long[] a = new long[N];
static long[] b = new long[N];
static long[] target = new long[N];
static Map<Long, Long>map = new HashMap<>();
public static void main(String[] args) {
new Thread(null, new Main(), "", 1 << 29).start();
}
public static int nextInt() throws IOException {
cin.nextToken();
return (int) cin.nval;
}
@Override
public void run() {
try {
n = nextInt();
for (int i = 1; i <= n; i++) {
a[i] = nextInt();
map.put(a[i], (long) i);
}
for (int i = 1; i <= n; i++) b[i] = nextInt();
long len = 0;target[(int) len] = 0;
for (int i = 1; i <= n; i++) {
if (target[(int) len] < map.get(b[i])) {
target[(int) ++len] = map.get(b[i]);
continue;
}
long l = 1; long r = len;
while(l <= r) {
long mid = (l + r) / 2;
if (target[(int) mid] < map.get(b[i])) {
l = mid + 1;
} else {
r = mid - 1;
}
}
target[(int) l] = map.get(b[i]);
}
cout.println(len);
cout.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
浙公网安备 33010602011771号