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;
else
f[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);
}
}