AcWing 4518. 最低票价
在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行。
在接下来的一年里,你要旅行的日子将以一个名为 days 的数组给出。
每一项是一个从 1 到 365 的整数。
火车票有三种不同的销售方式:
- 一张为期一天的通行证售价为 costs[0] 美元;
- 一张为期七天的通行证售价为 costs[1] 美元;
- 一张为期三十天的通行证售价为 costs[2] 美元。
通行证允许数天无限制的旅行。
例如,如果我们在第 22 天获得一张为期 7 天的通行证,那么我们可以连着旅行 7 天:第 2 天、第 3 天、第 4 天、第 5 天、第 6 天、第 7 天和第 8 天。
返回你想要完成在给定的列表 days中列出的每一天的旅行所需要的最低消费。
输入格式
第一行包含一个整数 n,表示 days 数组的长度。
第二行包含 n 个整数,表示 days[i]。
第三行包含 3 个整数,表示 costs[i]。
输出格式
一个整数,表示旅行所需要的最低消费。
数据范围
1≤n≤365,
1≤days[i]≤365,
daysdays 按顺序严格递增,
1≤costs[i]≤1000。
输入样例:
6
1 4 6 7 8 20 、
2 7 15
输出样例:
11
思路:
考虑状态表示为f[i]:前day[i]天旅行的最低消费
状态转移:f[i] = f[i - 1] + w[1]f[i] = Math.min(f[i], f[get(i, 7)] + w[2]f[i] = Math.min(f[i], f[get(i, 30)] + w[3]
import java.util.*;public class Main {static final int N = 400;static int[] d = new int[N];static int[] f = new int[N];static int n;static int[] w = new int[4];static int[] len = {0, 1, 7, 30};public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();for (int i = 1; i <= n; i++) {d[i] = sc.nextInt();}for (int i = 1; i <= 3; i++)w[i] = sc.nextInt();Arrays.fill(f, 0x3f3f3f3f);f[0] = 0;for (int i = 1; i <= n; i++) {for (int j = 1; j <= 3; j++) {f[i] = Math.min(f[i], f[get(i, len[j])] + w[j]);}}System.out.println(f[n]);}static int get(int i, int x) {int t = d[i] - x + 1;while (i > 0 && d[i] >= t)i--;return i;}}
AcWing 4496. 吃水果
n 个小朋友站成一排,等着吃水果。
一共有 m 种水果,每种水果的数量都足够多。
现在,要给每个小朋友都发一个水果,要求:在所有小朋友都拿到水果后,恰好有 k 个小朋友拿到的水果和其左边相邻小朋友拿到的水果不同(最左边的小朋友当然不算数,即最左边的小朋友不包含在 k 个小朋友内)。
请你计算,一共有多少种不同的分发水果的方案。
输入格式
一行,三个整数 n,m,k。
输出格式
一个整数,表示合理的分发水果的方案总数量对 998244353 取模后的结果。
数据范围
前 5 个测试点满足 1≤n,m≤5。
所有测试点满足 1≤n,m≤20001≤n,m≤2000,0≤k≤n−1。
输入样例1:
3 3 0
输出样例1:
3
输入样例2:
3 2 1
输出样例2:
4
思路:
方法1:DP
状态表示:f[i][j]表示前i个小朋友,恰有j个拿到的水果和其左边相邻的小朋友不同的方案数。
初始化:f[1][0] = m
状态转移:f[i][j] = f[i - 1][j] + (m - 1) * f[i - 1][j - 1]
static final int N = 2010, MOD = 998244353;static int[][] f = new int[N][N];static int n, m, k;static void solve() {n = ni();m = ni();k = ni();f[1][0] = m;for (int i = 2; i <= n; i++) {for (int j = 0; j < i; j++) {if (j > 0)f[i][j] = (int)(1L * (m - 1) * f[i - 1][j - 1] % MOD);f[i][j] = (f[i][j] + f[i - 1][j]) % MOD;}}out.println(f[n][k]);}
方法2:数学
先考虑共k + 1个小朋友,除第一个外,每个都与其左边的不同,方案数为
然后考虑固定第一个,剩余n - 1个位置如何放置k个小朋友,即
static final int N = 2010, MOD = 998244353;static int[][] f = new int[N][N];static int n, m, k;static void solve() {n = ni();m = ni();k = ni();if (m == 1) {if (k == 0) out.println(1);else out.println(0);return;}long s = m;for (int i = 1; i <= k; i++)s = s * (m - 1) % MOD;// c(n - 1, k) * s;int res = (int) (1L * fact[n - 1] * infact[k] % MOD * infact[n - 1 - k] % MOD * s % MOD);out.println(res);}static int[] fact = new int[N], infact = new int[N];static {fact[0] = infact[0] = 1;for (int i = 1; i < N; i++) {fact[i] = (int) (1L * fact[i - 1] * i % MOD);infact[i] = (int) (infact[i - 1] * qmi(i, MOD - 2, MOD) % MOD);}}static long qmi(long a, long b, long p) {long res = 1;while (b > 0) {if ((b & 1) == 1) {res = res * a % p;}a = a * a % p;b >>= 1;}return res;}
Acwing 2770. 方格取数

思路:
第一个难点在于状态定义f[i][j]表示所有从左上角走到达(i, j)且下一步向右走的路线的集和
属性:最大值
第二个难点在于状态转移的优化
先枚举列,再枚举行
枚举行时需要先从上往下,再从下往上计算两遍才可以遍历所有转移
import java.util.*;public class Main {static final int N = 1010;static int[][] a = new int[N][N];static long[][] f = new long[N][N];static int n, m;public static void main(String[] args) {Scanner sc = new Scanner(System.in);n = sc.nextInt();m = sc.nextInt();for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++) {a[i][j] = sc.nextInt();f[i][j] = (long)(-1e10);}int s = 0;for (int i = 1; i <= n; i++) {s += a[i][1];f[i][1] = s;}for (int j = 2; j <= m; j++) {long x = (long)(-1e10);for (int i = 1; i <= n; i++) {f[i][j] = Math.max(f[i][j - 1] + a[i][j], x + a[i][j]);x = f[i][j];}x = (long)(-1e10);for (int i = n; i >= 1; i--) {f[i][j] = Math.max(f[i][j], x + a[i][j]);x = Math.max(f[i][j - 1] + a[i][j], x + a[i][j]);}}System.out.println(f[n][m]);}}
京东20220827面试题t3
问长度为n的全由小写字母组成的字符串中,至少含2个"red"子串的方案数。1 <= n <= 1e6
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();if (n < 6) {System.out.println(0);return;}final int MOD = (int) (1e9 + 7);int[] a = new int[n + 1];int[][] f = new int[4][4];int[][] g = new int[4][4];int res = 1;for (int i = 0; i < n; i++)res = (int) ((res * 26L) % MOD);for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (i <= 2 && j <= 2)f[i][j] = 1;else if (i == 3 && j == 3)f[i][j] = 23 * 23;elsef[i][j] = 23;}}a[0] = 1;a[1] = 26;a[2] = 26 * 26;for (int idx = 3; idx <= n; idx++) {for (int k = 0; k < 4; k++) {for (int i = 0; i < 4; i++) {g[k][i] = 0;for (int j = 0; j < 4; j++) {if (k == 3) {g[k][i] = (int) ((g[k][i] + 23L * f[i][j] % MOD) % MOD);} else {if (!(k == 2 && i == 1 && j == 0))g[k][i] = (g[k][i] + f[i][j]) % MOD;}}}}int[][] t = f;f = g;g = t;int c = 0;for (int i = 0; i < 4; i++)for (int j = 0; j < 4; j++)c = (c + f[i][j]) % MOD;a[idx] = c;}int c = a[n];for (int i = 3; i <= n; i++) {int pre = i - 3, last = n - i;int x = a[pre] == 0 ? MOD : a[pre], y = a[last] == 0 ? MOD : a[last];c = (int) ((c + (long) (x) * y % MOD) % MOD);}System.out.println(((res - c) % MOD + MOD) % MOD);}}
