NENU 蓝桥杯训练赛(dp) 题解
f [ i ] [ j ] f[i][j] f[i][j] 表示前 i i i 个数 m o d mod mod k = = j k==j k==j 的最大值。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int k = cin.nextInt();
int a[] = new int[n + 1];
for(int i = 1;i <= n; ++i) {
a[i] = cin.nextInt();
}
int f[][] = new int[n + 1][k + 1];
for(int i = 1;i <= n; ++i) {
f[i][a[i] % k] = f[i - 1][0] + a[i];
for(int j = 1;j < k; ++j) {
if(f[i - 1][j] > 0)f[i][(j + a[i]) % k] = f[i - 1][j] + a[i];
}
for(int j = 0;j < k; ++j) {
f[i][j] = Math.max(f[i][j], f[i - 1][j]);
}
}
System.out.println(f[n][0]);
}
}
f [ i ] [ j ] f[i][j] f[i][j] 表示前 i i i 个数 m o d mod mod k = = j k==j k==j 是否可行。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int k = cin.nextInt();
int a[] = new int[n + 1];
for(int i = 1;i <= n; ++i) {
a[i] = cin.nextInt();
}
int f[][] = new int[n + 1][k + 1];
f[1][a[1] % k] = 1;
f[1][(-a[1] % k + k) % k] = 1;
for(int i = 2;i <= n; ++i) {
for(int j = 0;j < k; ++j) {
if(f[i - 1][j] == 1) {
f[i][(j + a[i]) % k] = 1;
f[i][((j - a[i]) % k + k) % k] = 1;
}
}
}
System.out.println(f[n][0] == 1 ? "YES" : "NO");
}
}
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示前 i i i 个精灵剩余精灵球为 j j j 剩余体力为 k k k 最多能捕获多少个精灵。
import java.io.*;
import java.util.*;
import java.math.*;
class pet {
int a, b;
pet(){
a = b = 0;
}
pet(int a, int b){
this.a = a;
this.b = b;
}
}
public class Main{
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int N = cin.nextInt();
int M = cin.nextInt();
int K = cin.nextInt();
pet s[] = new pet[K + 1];
for(int i = 1;i <= K; ++i) {
int a, b;
a = cin.nextInt();
b = cin.nextInt();
s[i] = new pet(a, b);
}
int f[][][] = new int[K + 1][N + 1][M + 1];
int ans1 = 0, ans2 = 0;
for(int i = 1;i <= K; ++i) {
for(int j = N;j >= 0; --j) {
for(int k = M;k >= 1; --k) {
if(j + s[i].a <= N && k + s[i].b <= M)f[i][j][k] = Math.max(f[i - 1][j][k], f[i - 1][j + s[i].a][k + s[i].b] + 1);
else {
f[i][j][k] = f[i - 1][j][k];
}
ans1 = Math.max(ans1, f[i][j][k]);
}
}
}
for(int i = 1;i <= K; ++i) {
for(int j = 0;j <= N; ++j) {
for(int k = 1;k <= M; ++k) {
if(f[i][j][k] == ans1) {
ans2 = Math.max(ans2, k);
}
}
}
}
System.out.println(ans1 + " " + ans2);
}
}
f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1] 表示第 i i i 个餐馆选或者不选的最大利润。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static int m[], p[], vs[][], f[][];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int T = cin.nextInt();
for(int ca = 1;ca <= T; ++ca) {
int n, k;
n = cin.nextInt();
k = cin.nextInt();
m = new int[n + 1];
p = new int[n + 1];
vs = new int[n + 1][n + 1];
f = new int[n + 1][2];
for(int i = 1;i <= n; ++i) {
m[i] = cin.nextInt();
}
for(int i = 1;i <= n; ++i) {
p[i] = cin.nextInt();
}
for(int i = 1;i <= n; ++i) {
f[i][1] = p[i];
for(int j = 1;j < i; ++j) {
f[i][0] = Math.max(f[i][0], Math.max(f[j][0], f[j][1]));
if(m[i] - m[j] > k) {
f[i][1] = Math.max(f[i][1], f[j][1] + p[i]);
}
}
}
System.out.println(Math.max(f[n][0], f[n][1]));
}
}
}
f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1] 表示前 i i i 位是 0 0 0 或者 1 1 1 的合法二进制的方案数。
非法方案数 = 总方案数 - 合法方案数
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static long f[][];
static long mod = 1000000007;
static long qpow(long x, long n) {
long res = 1;
x %= mod;
while(n > 0) {
if((n & 1) == 1) {
res = res * x % mod;
}
x = x * x % mod;
n >>= 1;
}
return res;
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
long ans = qpow(2, n);
f = new long[n + 1][n + 1];
f[0][0] = 1;
for(int i = 1;i <= n; ++i) {
f[i][0] = (f[i - 1][0] + f[i - 1][1]) % mod;
f[i][1] = f[i - 1][0];
}
ans = (ans - (f[n][0] + f[n][1]) % mod + mod) % mod;
System.out.println(ans);
}
}
f [ i ] [ j ] f[i][j] f[i][j] 表示 i i i 个人去北京 j j j 个人去上海的满意度。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static int f[][], B[], S[];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = n;
n <<= 1;
B = new int[n + 1];
S = new int[n + 1];
f = new int[n + 1][m + 1];
for(int i = 1; i <= n; ++i) {
B[i] = cin.nextInt();
S[i] = cin.nextInt();
}
for(int i = 0;i <= m; ++i) {
for(int j = 0;j <= m; ++j) {
if(i == 0 && j == 0)continue;
else if(i == 0)f[i][j] = f[i][j - 1] + S[i + j];
else if(j == 0)f[i][j] = f[i - 1][j] + B[i + j];
else {
f[i][j] = Math.max(f[i - 1][j] + B[i + j], f[i][j - 1] + S[i + j]);
}
}
}
System.out.println(f[m][m]);
}
}
f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1] 表示前 i i i 个人,第 i i i 个人匹配成功或者不成功的局数。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static int f[][], A[];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int k = cin.nextInt();
A = new int[n + 1];
for(int i = 1;i <= n; ++i) {
A[i] = cin.nextInt();
}
Arrays.sort(A, 1, n + 1);
f = new int[n + 1][2];
for(int i = 3;i <= n; ++i) {
f[i][0] = Math.max(f[i - 1][0], f[i - 1][1]);
if(A[i] - A[i - 2] <= k) {
f[i][1] = f[i - 2][0] + 1;
}
}
System.out.println(Math.max(f[n][0], f[n][1]));
}
}
因为是全排列,所以数组中不会出现两个相同的数。求最长公共子序列可以转化为求最长上升子序列问题。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static int f[][], p1[], p2[], pos[], ans[];
public static int lw(int a[], int st, int ed, int x) {
if(x > a[ed])return ed + 1;
int l = st, r = ed;
while(l < r) {
int mid = (l + r) >> 1;
if(a[mid] >= x) {
r = mid;
}
else {
l = mid + 1;
}
}
return l;
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
p1 = new int[n + 1];
p2 = new int[n + 1];
pos = new int[n + 1];
ans = new int[n + 1];
for(int i = 1;i <= n; ++i) {
p1[i] = cin.nextInt();
pos[p1[i]] = i;
}
int st = 1, ed = 0;
for(int i = 1;i <= n; ++i) {
p2[i] = cin.nextInt();
int x = pos[p2[i]];
int now = lw(ans, st, ed, x);
if(now > ed) {
ed = now;
}
ans[now] = x;
}
System.out.println(ed);
}
}
暴力。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static int f[][], a[];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int t = cin.nextInt();
a = new int[n + 1];
for(int i = 1;i <= n; ++i) {
a[i] = cin.nextInt();
}
int ans = 0;
for(int i = 0;i < (1 << n); ++i) {
int now = 0;
for(int j = 1;j <= n; ++j) {
if((i & (1 << (j - 1))) != 0) {
now += a[j];
}
}
if(now == t) {
ans++;
}
}
System.out.println(ans);
}
}
01 01 01 背包。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static int f[], w[], v[];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = cin.nextInt();
w = new int[n + 1];
v = new int[n + 1];
for(int i = 1;i <= n; ++i) {
w[i] = cin.nextInt();
v[i] = cin.nextInt();
}
f = new int[m + 1];
for(int i = 1;i <= n; ++i) {
for(int j = m;j >= w[i]; --j) {
f[j] = Math.max(f[j], f[j - w[i]] + v[i]);
}
}
System.out.println(f[m]);
}
}