提交 cd1d56a0 编写于 作者: qq_36480062's avatar qq_36480062

c

上级 672c71d1
package DFS.剪枝;
import java.util.Scanner;
/**
* https://blog.csdn.net/qq_30277239/article/details/105734349
*
* 搜索做数独
*/
public class 数独 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
s = sc.next();
}
static String s = "";
static String s;
}
###A*
```
A*可以处理任意边权,但不能有负环,需要保证一定有解!
启发式搜索,搜索空间很大,使用估价函数可以舍去很多,
无解情况会把搜索空间搜索一遍,不如BFS,因为pq是O(log n)
普通队列是O(1)
队列换成使用小根堆,
第一个存,从起点到当前点的真实距离,
第二个,从当前点到终点的估计距离
优先队列按照,起点到当前点的真实距离+当前点到终点的估计距离排序
while(!q.impty()){
t ->取出优先队列,队头
if 终点第一次出队的时候break
优先队列每次挑选预测距离最小的点扩展
for t的邻边
将邻边入队
}
特别像Dijkstra,把估价函数都取0,很像Dijkstra
证明:使得估算距离<=真实距离
......@@ -6,7 +6,7 @@ import java.util.StringTokenizer;
import static java.lang.System.in;
/**
* https://nekrozcoder.github.io/2019/07/28/%E3%80%90%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E3%80%91LCA%20%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/#more
* https://www.cnblogs.com/hulean/p/11144059.html
* 离线
* 预处理O(n)
* 单次查询O(1)
......
package RMQ;
import java.io.*;
import java.util.StringTokenizer;
import static java.lang.System.in;
/**
* 题目:https://www.acwing.com/problem/content/description/1276/
* https://www.acwing.com/file_system/file/content/whole/index/content/568662/
*/
public class 奶牛排队 {
public static void main(String[] args) throws IOException {
N = nextInt();
Q = nextInt();
for (int i = 1; i <= N; i++) {
h[i] = nextInt();
}
}
static void init() {
}
static int[] log = new int[23];
static int h[] = new int[50010];
static int N, Q;
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());
}
}
......@@ -12,7 +12,19 @@ public class KMP {
a = sc.next().toCharArray();
m = sc.nextInt();
p = sc.next().toCharArray();
int i = 0, j = 0;
init();
//j是匹配串
while (i < m && j < n) {
if (j == -1 || a[j] == p[i]) {
i++;
j++;
} else j = ne[j];
if (j == n) {
j = ne[j];
System.out.println(i - n);
}
}
}
static char[] a, p;
......
package String;
/**
* Hash Table
* 存储[213,12,412,3,12,3,12,3,12,3123]用数组存查询会O(n)
* 也可以排序O(n log n),使用二分O(log n)
* 查询数字存在与否,用[1...3133]这么大的空间存数字是否出现,查找时间O(1) 空间太大
* 所以使用hash table
* 建立hash函数 h(key)= key%23
* 只用A[0..22]数组快速查询,但可能会哈希冲突,
* 不同key使用h(key)算出来的值是可能一样的
* 对A[0...22]每个数组开个链表,到链表去查询,
* 也可以再来个hash函数再算得到新的位置
*/
public class 哈希表 {
static class node {
int next, info;
public node(int next, int info) {
this.next = next;
this.info = info;
}
}
public static void main(String[] args) {
add(99123, 23);
add(99123, 22);
System.out.println(find(99123,23));
}
static void add(int key, int info) {
int u = key % M;
nodes[tot] = new node(h[u], info);
h[u] = tot++;
}
static int find(int key, int info) {
int u = key % M;
for (int i = h[u]; i != 0; i = nodes[i].next) {
if (nodes[i].info == info) {
return 1;
}
}
return 0;
}
static int N = 123, tot = 1, M = 23;
static int[] h = new int[N];
static node[] nodes = new node[N];
}
......@@ -55,46 +55,60 @@ public class 单调队列 {
for (int i = 0; i < n; i++) {
a[i] = nextInt();
}
long s = System.nanoTime();
List();
long t = System.nanoTime();
System.out.println((t - s));
s = System.nanoTime();
int head = 0, end = -1;
// List();
// int head = 0, end = -1;
// for (int i = 0; i < n; i++) {
// if (head <= end && q[head] < i - k + 1) head++;
// //队列里面的元素不在窗口内,就删除该元素
// //i-k+1是当前窗口的第一个值的下标
// while (head <= end && a[q[end]] >= a[i]) end--;
// //如果队列尾部的值大于新加进来的值,就删除队尾元素,
// //对应的是队尾指针前移
// q[++end] = i;
// //把新元素插入到队尾
// if (i >= k - 1) System.out.println(a[q[head]]);
// }
// t = System.nanoTime();
// System.out.println((t - s));
int hh = 0, tt = -1;
for (int i = 0; i < n; i++) {
if (head <= end && q[head] < i - k + 1) head++;
//队列里面的元素不在窗口内,就删除该元素
//i-k+1是当前窗口的第一个值的下标
while (head <= end && a[q[end]] >= a[i]) end--;
//如果队列尾部的值大于新加进来的值,就删除队尾元素,
//对应的是队尾指针前移
q[++end] = i;
//把新元素插入到队尾
if (i >= k - 1) System.out.println(a[q[head]]);
if (hh <= tt && q[hh] < i - k + 1) hh++;
while (hh <= tt && a[q[tt]] >= a[i]) tt--;
q[++tt] = i;
if (i >= k - 1) bw.write(a[q[hh]] + " ");
}
t = System.nanoTime();
System.out.println((t - s));
hh = 0;
bw.write("\n");
tt = -1;
for (int i = 0; i < n; i++) {
if (hh <= tt && q[hh] < i + k + 1) hh++;
while (hh <= tt && a[q[tt]] <= a[i]) tt--;
q[++tt] = i;
if (i >= k - 1) bw.write(a[q[hh]] + " ");
}
bw.flush();
}
//链表实现队列,慢一些相较于数组模拟队列
static void List() throws IOException {
queue.clear();
for (int i = 0; i < n; i++) {
if (!queue.isEmpty() && a[queue.peekFirst()] < i - k + 1) queue.removeFirst();
while (!queue.isEmpty() && a[queue.peekLast()] > a[i]) queue.removeLast();
queue.add(i);
if (!queue.isEmpty() && i >= k - 1) bw.write(a[queue.peekFirst()] + " ");
if (!queue.isEmpty() && queue.peekFirst() < i - k + 1) queue.removeFirst();
while (!queue.isEmpty() && a[queue.peekLast()] >= a[i]) queue.removeLast();
queue.addLast(i);
if (i >= k - 1 && !queue.isEmpty()) bw.write(a[queue.peekFirst()] + " ");
}
bw.write("\n");
queue.clear();
for (int i = 0; i < n; i++) {
if (!queue.isEmpty() && queue.peekFirst() < i - k + 1) queue.removeFirst();
while (!queue.isEmpty() && a[queue.peekLast()] <= a[i]) queue.removeLast();
queue.add(i);
queue.addLast(i);
if (i >= k - 1 && !queue.isEmpty()) bw.write(a[queue.peekFirst()] + " ");
}
bw.flush();
System.out.println();
}
static int[] a = new int[(int) (1e6 + 10)];
......
package dp.单调队列dp;
import java.util.Scanner;
/**
* 在一年前赢得了小镇的最佳草坪比赛后,FJ 变得很懒,
* 再也没有修剪过草坪。
* 现在,新一轮的最佳草坪比赛又开始了,FJ 希望能够再次夺冠。
* 然而,FJ 的草坪非常脏乱,
* 因此,FJ 只能够让他的奶牛来完成这项工作。
* FJ 有 N 只排成一排的奶牛,编号为 1 到 N。
* 每只奶牛的效率是不同的,奶牛 i 的效率为 Ei。
* 编号相邻的奶牛们很熟悉,如果 FJ 安排超过 K 只编号连续的奶牛,
* 那么这些奶牛就会罢工去开派对。
* 因此,现在 FJ 需要你的帮助,找到最合理的安排方案并计算 FJ 可以得到的最大效率。
* 注意,方案需满足不能包含超过 K 只编号连续的奶牛。
* 输入格式
* 第一行:空格隔开的两个整数 N 和 K;
* 第二到 N+1 行:第 i+1 行有一个整数 Ei。
* 输出格式
* 共一行,包含一个数值,表示 FJ 可以得到的最大的效率值。
* 数据范围
* 1≤N≤10^5
* 0≤Ei≤10^9
* 输入样例:
* 5 2
* 1
* 2
* 3
* 4
* 5
* 输出样例:
* 12
* 样例解释
* FJ 有 5 只奶牛,效率分别为 1、2、3、4、5。
* FJ 希望选取的奶牛效率总和最大,但是他不能选取超过 2 只连续的奶牛。
* 因此可以选择第三只以外的其他奶牛,总的效率为 1 + 2 + 4 + 5 = 12。
* f[i]表示从前i头牛中选,且合法的所有方案
* 属性:max
* f[i]第i头牛选还是不选作为划分依据
* 选上第i头,继续划分,包括i往前连续长度不超过K的最大,长度为 1 2 ...K
* f[i]=max{ f[i-j-1]-s[i-j] |1<=j<=k }+s[i]
* 不选上第i头,从前i-1头选合法,为f[i-1]
*/
public class 修剪草坪 {
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++) {
s[i] = sc.nextInt() + s[i - 1];
}
int hh = 0, tt = 0;
for (int i = 1; i <= n; i++) {
if (q[hh] < i - m) hh++;
f[i] = Math.max(f[i - 1], g(q[hh]) + s[i]);
while (hh <= tt && g(q[tt]) <= g(i)) tt--;
q[++tt] = i;
}
System.out.println(f[n]);
}
static int g(int i) {
if (i - 1 < 0) return 0;
return f[i - 1] - s[i];
}
static int n, m, N = (int) (1e5 + 10);
static int[] s = new int[N];
static int[] q = new int[N];
static int[] f = new int[N];
}
package dp.单调队列dp;
import java.io.*;
import java.util.StringTokenizer;
import static java.lang.System.in;
/**
* https://blog.csdn.net/qq_30277239/article/details/104578677
* John 打算驾驶一辆汽车周游一个环形公路。
* 公路上总共有 n 个车站,每站都有若干升汽油(有的站可能油量为零),每升油可以让汽车行驶一千米。
* John 必须从某个车站出发,一直按顺时针(或逆时针)方向走遍所有的车站,并回到起点。
* 在一开始的时候,汽车内油量为零,John 每到一个车站就把该站所有的油都带上(起点站亦是如此),
* 行驶过程中不能出现没有油的情况。
* 任务:判断以每个车站为起点能否按条件成功周游一周。
* 输入格式
* 第一行是一个整数 n,表示环形公路上的车站数;
* 接下来 n 行,每行两个整数 pi,di,分别表示表示第 i 号车站的存油量和第 i 号车站到下一站的距离。
* 输出格式
* 输出共 n 行,如果从第 i 号车站出发,一直按顺时针(或逆时针)方向行驶,能够成功周游一圈,则在第 i 行输出 TAK,否则输出 NIE。
* 数据范围
* 3≤n≤10^6,
* 0≤pi≤2×10^9,
* 0<di≤2×10^9
* 输入样例:
* 5
* 3 1
* 1 2
* 5 2
* 0 1
* 5 4
* 输出样例:
* TAK
* NIE
* TAK
* NIE
* TAK
* 环展开成链
*/
public class 旅行问题 {
public static void main(String[] args) throws IOException {
n = nextInt();
for (int i = 1; i <= n; i++) {
a[i] = nextInt();
b[i] = nextInt();
}
for (int i = 1; i <= n; i++) {
}
}
static int[] q = new int[(int) (2e6 + 10)];
static long[] a = new long[(int) (2e6 + 10)];
static long[] b = new long[(int) (2e6 + 10)];
static int n;
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());
}
}
package dp.单调队列dp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.StringTokenizer;
/**
* 输入一个长度为n的整数序列,从中找出一段长度不超过m的连续子序列,使得子序列中所有数的和最大。
* 输入格式
* 第一行输入两个整数n,m。
* 第二行输入n个数,代表长度为n的整数序列。
* 同一行数之间用空格隔开。
* 输出格式
* 输出一个整数,代表该序列的最大子序和。
* 数据范围
* 1≤n,m≤300000
* 输入样例:
* 6 4
* 1 -3 5 1 -2 3
* 输出样例:
* 7
* 只能用单调队列优化,其他都会超时,
* 有限集合求最值,求个数
* 所有长度不超过m的子序列,按照m的终点来分类,分成n类,不重不漏,
* 求得每一类最大值,取max
* 假设以A[k]结尾,往前枚举,长度1的,长度2的,长度3...
* 结合区间和数组为S[],那么以A[k]结尾,长度为j的子序列和为,
* S[k]-S[k-j](1<=j<=m)
*/
public class 最大序列和 {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
n = nextInt();
m = nextInt();
for (int i = 1; i <= n; i++) {
s[i] = nextInt() + s[i - 1];
}
f();
}
/**
* 单调队列一般存下标,
* 因为这个可以让我们快速判断当前位置是否已经划出窗口了
*/
static void f() {
int res = (int) -1e8;
int hh = 0, tt = 0;
//tt初始化为0,数组初始化不为空,说明队列中有一个元素s[0],当然s[0]=0
//因为S[k]-S[k-j](1<=j<=m), 存在k<=m 也就是,结果S[k]-0,然而取max为s[i]-s[q[hh]],
//这么写最简单
for (int i = 1; i <= n; i++) {
if (q[hh] < i - m) hh++;
res = Math.max(res, s[i] - s[q[hh]]);
while (hh <= tt && s[q[tt]] >= s[i]) tt--;
//考虑S[k]-S[k-j](1<=j<=m),S[k-j]应该越小越好
q[++tt] = i;//当前元素加到队列当中
}
System.out.println(res);
}
static int[] q = new int[300010];
static int[] s = new int[300009];
static int n, m;
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokenizer = new StringTokenizer("");
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());
}
}
package dp.单调队列dp;
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;
import static java.lang.System.in;
/**
* https://blog.csdn.net/qq_30277239/article/details/104580927
* f[i]表示前1~i且点燃第i个烽火台,
* 属性:最小代价
* f[i]找倒数第2个, i-1 i-2...i-m+1 i-m
* f[i]=min(f[j] | i-m<=j<i )+w[i] 单调队列优化
*/
public class 烽火传递 {
public static void main(String[] args) throws IOException {
n = nextInt();
m = nextInt();
for (int i = 1; i <= n; i++) {
a[i] = nextInt();
}
ydp();
f();
}
//单调队列dp
static void ydp() {
int hh = 0, tt = 0;
int[] q = new int[(int) (2e5 + 10)];
for (int i = 1; i <= n; i++) {
if (i - q[hh] > m) hh++;
f[i] = f[q[hh]] + a[i];
while (hh <= tt && f[i] <= f[q[tt]]) tt--;
q[++tt] = i;
System.out.print(f[i] + " ");
}
System.out.println();
int res = (int) 1e9;
for (int i = n - m + 1; i <= n; i++) {
res = Math.min(res, f[i]);
}
System.out.println(res);
}
//朴素dp
public static void f() {
for (int i = 1; i <= n; i++) {
if (i <= m) {
f[i] = a[i];
} else {
int t = f[i - 1];
for (int j = i - m; j < i - 1; j++) {
t = Math.min(f[j], t);
}
f[i] = t + a[i];
}
}
System.out.println(Arrays.toString(f));
System.out.println(f[n]);
}
static int[] f = new int[(int) (2e5 + 10)];
static int[] a = new int[(int) (2e5 + 10)];
static int n, m;
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());
}
}
package dp.单调队列dp;
import java.util.Scanner;
/**
* https://blog.csdn.net/qq_30277239/article/details/104590017
* 有一个 a×b的整数组成的矩阵,
* 现请你从中找出一个 n×n的正方形区域,
* 使得该区域所有数中的最大值和最小值的差最小。
* 输入格式
* 第一行为三个整数,分别表示 a,b,n的值;
* 第二行至第 a+1 行每行为 b 个非负整数,
* 表示矩阵中相应位置上的数。
* 输出格式
* 输出仅一个整数,
* 为 a×b 矩阵中所有“n×n 正方形区域中的最大整数和最小整数的差值”的最小值。
* 数据范围
* 2≤a,b≤1000,
* n≤a,n≤b,n≤100,
* 矩阵中的所有数都不超过 10^9。
* 输入样例:
* 5 4 2
* 1 2 5 6
* 0 17 16 0
* 16 17 2 1
* 2 10 2 1
* 1 2 2 2
* 输出样例:
* 1
* 先预处理求每行的最值,在预处理列
*/
public class 理想的正方形 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
k = sc.nextInt();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
w[i][j] = sc.nextInt();
}
}
for (int i = 1; i <= n; i++) {
}
}
static void getMin(int[] a, int[] b, int tot) {
int hh = 0, tt = -1;
for (int i = 1; i <= tot; i++) {
if (hh <= tt && q[hh] <= i - tot) hh++;
while (hh <= tt && a[q[tt]] >= a[i]) tt--;
q[++tt] = i;
b[i] = a[q[hh]];
}
}
static void getMax(int[] a, int[] b, int tot) {
int hh = 0, tt = -1;
for (int i = 1; i <= tot; i++) {
if (hh <= tt && q[hh] <= i - tot) hh++;
while (hh <= tt && a[q[tt]] <= a[i]) tt--;
q[++tt] = i;
b[i] = a[q[hh]];
}
}
static int n, m, k, N = 1010;
static int[] q = new int[N];
static int[][] w = new int[N][N];
static int[][] row_max = new int[N][N];
static int[][] row_min = new int[N][N];
}
package dp.单调队列dp;
import java.util.Scanner;
/**
* https://blog.csdn.net/qq_30277239/article/details/104582203
* 数学《绿色通道》总共有 n 道题目要抄,编号 1,2,…,n,抄第 i 题要花 ai 分钟。
* 小 Y 决定只用不超过 t 分钟抄这个,因此必然有空着的题。
* 每道题要么不写,要么抄完,不能写一半。
* 下标连续的一些空题称为一个空题段,它的长度就是所包含的题目数。
* 这样应付自然会引起马老师的愤怒,最长的空题段越长,马老师越生气。
* 现在,小 Y 想知道他在这 t 分钟内写哪些题,才能够尽量减轻马老师的怒火。
* 由于小 Y 很聪明,你只要告诉他最长的空题段至少有多长就可以了,不需输出方案。
* 输入格式
* 第一行为两个整数 n,t。
* 第二行为 n 个整数,依次为 a1,a2,…,an。
* 输出格式
* 输出一个整数,表示最长的空题段至少有多长。
* 数据范围
* 0<n≤5×10^4,
* 0<ai≤3000,
* 0<t≤10^8
* 输入样例:
* 17 11
* 6 4 5 2 5 3 4 5 2 3 4 5 2 3 6 3 5
* 输出样例:
* 3
* 二分+单调队列,求空题段长度的最小值是多少
*
* 本题的难点在于解题的方向,如果看到题目把时间限制t当做背包容量,
* 然后考虑每道题选与不选来求最长空题段最短是多少,状态机需要涉及选与不选,
* 已经消耗的时间,目前最长的空题段,较为复杂。但是换个思路想想,
* 最长空题段的长度可能是1到n,
* 只要在最长空题段不超过某个长度len的前提下消耗的最少时间不超过t,
* 那么这个len就是合法的,可以用二分法来枚举可能的解,从这个方向考虑问题就会简单很多,
* 因为求空题段长度不超过len的最小消耗时间与上一题AcWing 1089 烽火传递基本一致。
*/
public class 绿色通道 {
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++) {
w[i] = sc.nextInt();
}
int l = 0, r = n;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
System.out.println(l);
}
private static boolean check(int limit) {
int tt = 0, hh = 0;
for (int i = 1; i <= n; i++) {
if (q[hh] < i - limit - 1) hh++;
f[i] = f[q[hh]] + w[i];
while (hh <= tt && f[q[tt]] >= f[i]) tt--;
q[++tt] = i;
}
for (int i = n - limit; i <= n; i++) {
if (f[i] <= m) {
return true;
}
}
return false;
}
static int n, m, N = 50005;
static int[] w = new int[N], f = new int[N], q = new int[N];
}
......@@ -83,6 +83,15 @@ public class 大盗阿福 {
}
//状态机
/**
* 状态转移,看成图论问题
* f[i,0] f[i,1] 表示:所有走了i步,且当前位于状态j的所有走法
* 属性:max
* 状态计算:f[i,0] 0->0 上一个不偷,这个一个也不偷, f[i-1,0]
* 1->0 上一个偷了,这个不偷 f[i-1,1]
* f[i,1] 状态计算,只能0->1 上个不偷这个偷,f[i-1,0]+w[i]
*/
static void fin() {
Scanner sc = new Scanner(System.in);
t = sc.nextInt();
......
......@@ -60,6 +60,10 @@ public class 股票买卖4 {
O3();
}
/**
* f[i,j,0]表示第i天已经进行了j次交易且此时未持仓,
* f[i][j][1]表示到第i天已经进行了j次交易且此时持有仓位。
*/
static void O3() {
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= k; j++) {
......@@ -67,7 +71,7 @@ public class 股票买卖4 {
f[i][j][l] = Integer.MIN_VALUE / 2;
}
}
}
}//初始化负无穷
f[0][0][0] = 0;
for (int i = 1; i <= n; i++) {
f[i][0][0] = 0;
......@@ -75,6 +79,7 @@ public class 股票买卖4 {
f[i][j][0] = Math.max(f[i - 1][j][0], f[i - 1][j][1] + a[i]);
//卖出不消耗次数
f[i][j][1] = Math.max(f[i - 1][j][1], f[i - 1][j - 1][0] - a[i]);
//昨天买的,今天不卖, 昨天交易次数为j-1没买,今天买上
//买入消耗次数
}
}
......
......@@ -49,6 +49,9 @@ public class 股票买卖5 {
/**
* dp.状态机模型
* https://blog.csdn.net/qq_30277239/article/details/104161014
* f[i,0] 第i天手中有货
* f[i,1] 手中无货的第1天,无法购买
* f[i,2] 手中无货的第>=2天,可以购买
*/
static void time() {
dp[0][0] = dp[0][1] = (int) -1e9;//非法方案
......@@ -57,7 +60,7 @@ public class 股票买卖5 {
dp[i][1] = dp[i - 1][0] + a[i];
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1]);
}
System.out.println(Math.max(dp[n][1], dp[n][2]));
System.out.println(Math.max(dp[n][1], dp[n][2]));//两个出口
}
static int[][] dp = new int[(int) (1e5 + 10)][3];
......
package dp.状态机模型;
import java.util.Arrays;
import java.util.Scanner;
/**
*
* https://www.acwing.com/solution/content/16353/
* https://blog.csdn.net/qq_30277239/article/details/104189713
*/
public class 设计密码 {
static int mod = (int) (1e9 + 7);
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
f[0][0] = 1;
n = sc.nextInt();
p = sc.next().toCharArray();
m = p.length;
f();
int t = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
for (char k = 'a'; k <= 'z'; k++) {
t = j;
while (t != -1 && p[t] != k) t = ne[t];
t++;
if (t < m) f[i + 1][t] = (f[i + 1][t] + f[i][j])%mod;
}
}
}
int res = 0;
for (int i = 0; i < m; i++) {
res = (res+f[n][i])%mod;
}
System.out.println(res);
}
static int[] ne = new int[55];
static int n, m;
static char[] p;
static int[][] f = new int[66][66];
static void f() {
ne[0] = -1;
int t = 0;
for (int i = 1; i <= m; i++) {
t = ne[i - 1];
while (t != -1 && p[i - 1] != p[t]) t = ne[t];
ne[i] = t + 1;
}
}
}
......@@ -83,23 +83,23 @@ public class 二维费用背包收服小精灵 {
}
}
System.out.println(dp[n][N][M - 1]);
int k = M-1;
while (k > 0 && dp[n][N][k - 1] == dp[n][N][M-1]) k--;
int k = M - 1;
while (k > 0 && dp[n][N][k - 1] == dp[n][N][M - 1]) k--;
System.out.println(M - k);
}
static void two() {
for (int i = 1; i <= n; i++) {
for (int j = N; j >= v1[i]; j--) {
for (int k = M-1; k >= v2[i]; k--) {
for (int k = M - 1; k >= v2[i]; k--) {
f[j][k] = Math.max(f[j - v1[i]][k - v2[i]] + 1, f[j][k]);
}
}
}
System.out.println(f[N][M-1]);
System.out.println(f[N][M - 1]);
//因为
int k = M-1;
while (k > 0 && f[N][k-1] == f[N][M-1]) k--;
int k = M - 1;
while (k > 0 && f[N][k - 1] == f[N][M - 1]) k--;
System.out.println(M - k);
}
......
package graph.Floyd;
/**
* https://blog.csdn.net/qq_30277239/article/details/107301496
* https://www.cnblogs.com/ctyakwf/p/12829458.html
*/
public class 牛的旅行 {
......
###拓扑排序
````
入度为0的点加入队列,取出入度为0的点,并减去该点相邻的入度,
队列中实际上是存的所有入度为0的点,使用pq可以达到字典序
知道队列没有元素,该题一定有解,无解情况用vis判断,
技巧,拓扑排序使得字典序最小,使用优先队列
因为队列中存的是目前所有度数为0的点
......@@ -2,7 +2,26 @@ package graph.topoSort;
/**
* https://www.hzxueyan.com/archives/104/
*
* 由于无敌的凡凡在 2005 年世界英俊帅气男总决选中胜出,Yali Company 总经理 Mr.Z 心情好,决定给每位员工发奖金。
* 公司决定以每个人本年在公司的贡献为标准来计算他们得到奖金的多少。
* 于是 Mr.Z 下令召开 m 方会谈。
* 每位参加会谈的代表提出了自己的意见:“我认为员工 a 的奖金应该比 b高!”
* Mr.Z 决定要找出一种奖金方案,满足各位代表的意见,且同时使得总奖金数最少。
* 每位员工奖金最少为 100 元,且必须是整数。
* 输入
* 第一行包含整数 n, m分别表示公司内员工数以及参会代表数。
* 接下来 m 行,每行 2 个整数 a,b,表示某个代表认为第 a 号员工奖金应该比第 b号员工高。
* 输出
* 若无法找到合理方案,则输出Poor Xed;
* 否则输出一个数表示最少总奖金。
* 数据范围
* 1≤n≤10000
* 1≤m≤20000
* 输入样例
* 2 1
* 1 2
* 输出样例
* 201
*/
public class 奖金 {
public static void main(String[] args) {
......
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Scanner;
/**
* 这道题一定有解
* 拓扑排序
* https://www.hzxueyan.com/archives/103/
* 入度为0的点加入队列,取出入度为0的点,并减去该点相邻的入度,
......@@ -28,7 +29,7 @@ public class 家谱树 {
}
private static void topo() {
ArrayList<Integer> g = new ArrayList<Integer>();
ArrayList<Integer> g = new ArrayList<Integer>();//拓扑排序的结果
ArrayDeque<Integer> q = new ArrayDeque<Integer>();
for (int i = 1; i <= n; i++) {
if (in[i] == 0) {
......@@ -48,7 +49,7 @@ public class 家谱树 {
}
}
for (Integer w : g) {
System.out.println(w);
System.out.print(w + " ");
}
}
......
......@@ -47,7 +47,7 @@ public class 最小花费 {
@Override
public int compareTo(node node) {
return (int) (x * 1000 - node.x * 10000);
return (int) (x * 10000 - node.x * 10000);
}
}
......
......@@ -7,6 +7,7 @@ import java.util.Scanner;
/**
* http://blog.sina.com.cn/s/blog_83ac6af80102v0zj.html
* https://blog.csdn.net/qq_30277239/article/details/106104598
* 裸最短路
*/
public class 热浪 {
......
......@@ -2,6 +2,7 @@ package graph.单源最短路;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
/**
......@@ -15,6 +16,8 @@ import java.util.Scanner;
* 2 3 7
* 2 4 3
* 3 4 5
* out:
* 8
* 选一个节点作为起点使得其他节点到该节点的所有步数最少,显然
* 多源汇最短路,n为500 Floyd O(n^3)超时
* 使用spfa
......@@ -75,6 +78,49 @@ public class 香甜的黄油 {
return res;
}
static int Dijkstra(int s) {
int res = 0;
PriorityQueue<node> q = new PriorityQueue<node>();
Arrays.fill(dis, Integer.MAX_VALUE / 2);
Arrays.fill(vis, false);
dis[s] = 0;
q.add(new node(0, s));
while (!q.isEmpty()) {
int p = q.poll().to;
//pq每次取出的边,就是算出最短路径的边
if (vis[p]) continue;
vis[p] = true;
for (int i = he[p]; i != 0; i = ne[i]) {
int ed = e[i];
if (dis[p] != Integer.MAX_VALUE && dis[ed] > dis[p] + w[i]) {
dis[ed] = dis[p] + w[i];
q.add(new node(ed, dis[ed]));
}
}
}
for (int i = 0; i < n; i++) {
int j = id[i];
if (dis[j] == Integer.MAX_VALUE / 2) return Integer.MAX_VALUE / 2;
//无法到达
res += dis[j];
}
return res;
}
static class node implements Comparable<node> {
int dis, to;
public node(int dis, int to) {
this.dis = dis;
this.to = to;
}
@Override
public int compareTo(node node) {
return dis - node.dis;
}
}
static int ans = Integer.MAX_VALUE;
static void add(int a, int b, int c) {
......
package graph.复合单源最短路;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Scanner;
/**
* https://www.acwing.com/file_system/file/content/whole/index/content/533831/
* https://www.cnblogs.com/wulichenai/p/12694599.html
* 从a到b,路径的长度定义为第k+1大值
* 二分:
*
* 二分:定义在[0,1000001]区间性质为
* 对于区间中的某一个点x
* 求出1~N中最少经过几条长度大于x的边,假设最少经过y条,
* (最少经过多少条大于x的边的数量是否小于等于k)
* 把边长大于x的看做1,否则看做0
* 用双端队列bfs
*/
public class 通信线路 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
k = sc.nextInt();
int a, b, c;
while (m-- != 0) {
a = sc.nextInt();
b = sc.nextInt();
c = sc.nextInt();
add(a, b, c);
add(b, a, c);
}
int l = 0, r = (int) (1e6 + 1);
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
if (r == 1e6 + 1) r = -1;
System.out.println(r);
}
private static boolean check(int bound) {
Arrays.fill(st, false);
Arrays.fill(dis, Integer.MAX_VALUE / 2);
dis[1] = 0;
q.add(1);
while (!q.isEmpty()) {
int t = q.poll();
if (st[t]) continue;
st[t] = true;
for (int i = he[t]; i != 0; i = ne[i]) {
int j = e[i], v = w[i] > bound ? 1 : 0;
if (dis[j] > dis[t] + v) {
dis[j] = dis[t] + v;
if (v == 0) q.addFirst(j);
else q.addLast(j);
}
}
}
return dis[n] <= k;
}
static int n, m;
static void add(int a, int b, int c) {
e[cnt] = b;
w[cnt] = c;
ne[cnt] = he[a];
he[a] = cnt++;
}
static int n, m, N = 1010, M = 20010, cnt = 1, k;
static int[] he = new int[N];
static int[] ne = new int[M];
static int[] w = new int[M];
static int[] e = new int[M];
static int[] dis = new int[N];
static ArrayDeque<Integer> q = new ArrayDeque<Integer>();
static boolean[] st = new boolean[N];
}
package graph.复合单源最短路;
import java.util.Scanner;
/**
* 如果边权非负使用Dijkstra算法
*
* spfa会被卡
* 把双向的非负块节点,用Dijkstra算法
* 把一群节点,看做一个节点块
*/
public class 道路与航路 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
}
}
````
最小生成树:边权之和最小
````
##Prim
##Prim 针对无向边
````
朴素Prim O(n^2) 使用邻接矩阵存图
堆优化 Prim 被Kruskal完爆
````
###Kruskal 稀疏图
###Kruskal 稀疏图 针对无向边
````
O(m log n)
直接存边
并查集
......
......@@ -6,7 +6,7 @@ import java.util.Scanner;
/**
* https://www.acwing.com/activity/content/code/content/308366/
* 求出无向图最小生成树中,最长边权的最小值
* 最小生成树必然是n-1条边,
* 最小生成树的权值最大的边,对应Kruskal就是最后取到的那条边
*/
public class 繁忙的都市 {
public static void main(String[] args) {
......@@ -29,7 +29,7 @@ public class 繁忙的都市 {
ans = p.w;
}
}
System.out.println(n-1+" "+ans);
System.out.println(n - 1 + " " + ans);
}
static void union(int x, int y) {
......
package 数学;
import java.util.Scanner;
/**
* https://www.acwing.com/solution/acwing/content/8155/
* 哥德巴赫猜想的内容如下:
* 任意一个大于 4 的偶数都可以拆成两个奇素数之和。
* 例如:
* 8=3+5
* 20=3+17=7+13
* 42=5+37=11+31=13+29=19+23
* 现在,你的任务是验证所有小于一百万的偶数能否满足哥德巴赫猜想。
* 输入格式
* 输入包含多组数据。
* 每组数据占一行,包含一个偶数 n。
* 读入以 0 结束。
* 输出格式
* 对于每组数据,输出形如 n = a + b,其中 a,b 是奇素数。
* 若有多组满足条件的 a,b,输出 b−a 最大的一组。
* 若无解,输出 Goldbach’s conjecture is wrong.。
* 数据范围
* 6≤n<106
* 输入样例:
* 8
* 20
* 42
* 0
* 输出样例:
* 8 = 3 + 5
* 20 = 3 + 17
* 42 = 5 + 37
* 预处理1e6以内的素数,从小到大枚举素数,则分解的两数相差最大
*/
public class 哥德巴赫猜想 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
f();
while (sc.hasNext()) {
int n = sc.nextInt();
if (n == 0) break;
for (int i = 1; ; i++) {
int a = primer[i];
int b = n - a;
if (!vis[b]) {
System.out.println(n + " " + a + "+" + b);
break;
}
}
}
}
static int[] primer = new int[(int) (1e6 + 10)];
static boolean[] vis = new boolean[(int) (1e6 + 10)];
static void f() {
int cnt = 0;
for (int i = 2; i <= 1e6; i++) {
if (!vis[i]) primer[cnt++] = i;
for (int j = 0; primer[j] * i <= 1e6; j++) {
vis[primer[j] * i] = true;
if (i % primer[j] == 0) break;
//如果这个质数是i的最小质因子,就break
}
}
}
}
package 数学;
/**
*
*/
public class 埃氏筛法 {
public static void main(String[] args) {
long s = System.nanoTime();
f(12345678);
long t = System.nanoTime();
System.out.println((t - s )/ 1e8);
s=System.nanoTime();
euler(12345678);
t=System.nanoTime();
System.out.println((t-s)/1e8);
System.out.println();
}
static int[] primer = new int[99999991];
/**
* 埃氏筛法求n以内的质数
* 调和级数极限为 ln n+C C为euler 常数
* 不加优化是O(n log n) 加上是O(n log log n)
* 1+1/2+1/3+...
*
* @param n
*/
static void f(int n) {
int cnt = 0;
boolean[] vis = new boolean[n + 1];
for (int i = 2; i <= n; i++) {
if (!vis[i]) primer[cnt++] = i;
else continue;//只需要筛所有质数的倍数
for (int j = 2 * i; j <= n; j += i) {
vis[j] = true;
}
}
System.out.println(primer[cnt-1]);
}
/**
* @param n
*/
static void euler(int n) {
boolean[] vis = new boolean[n + 1];
int cnt = 0;
System.out.println();
for (int i = 2; i <= n; i++) {
if (!vis[i]) primer[cnt++] = i;
//把i的质数倍筛出去
for (int j = 0; primer[j] * i <= n; j++) {
vis[primer[j] * i] = true;
if (i % primer[j] == 0) break;
}
}
System.out.println(primer[cnt-1]);
}
}
package 数学;
import java.util.Scanner;
/**
* https://www.acwing.com/solution/content/9536/
* 夏洛克有了一个新女友(这太不像他了!)。
* 情人节到了,他想送给女友一些珠宝当做礼物。
* 他买了 n 件珠宝,第 i 件的价值是 i+1,也就是说,珠宝的价值分别为 2,3,…,n+1。
* 华生挑战夏洛克,让他给这些珠宝染色,使得一件珠宝的价格是另一件珠宝的价格的质因子时,两件珠宝的颜色不同。
* 并且,华生要求他使用的颜色数尽可能少。
* 请帮助夏洛克完成这个简单的任务。
* 输入格式
* 只有一行一个整数 n,表示珠宝件数。
* 输出格式
* 第一行一个整数 k,表示所使用的颜色数;
* 第二行 n 个整数,表示第 1 到第 n 件珠宝被染成的颜色。
* 若有多种答案,输出任意一种。
* 请用 1 到 k 表示你用到的颜色。
* 数据范围
* 1≤n≤100000
* 输入样例1:
* 3
* 输出样例1:
* 2
* 1 1 2
* 输入样例2:
* 4
* 输出样例2:
* 2
* 2 1 1 2
* 分析:质数连合数,连一条边,是二分图,最多需要2种颜色
* 左边是质数,右边是合数,合数必然有质因子,可能不止一个,但满足二分图!!!
*/
public class 夏洛克和他的女朋友 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
if (n <= 2) {
System.out.println(1);
} else System.out.println(2);
n++;
f();
for (int i = 2; i <= n; i++) {
if (!st[i]) System.out.print("1 ");
else System.out.print("2 ");
}
}
static boolean[] st = new boolean[(int) 1e6];
static int[] primer = new int[(int) 1e6];
static int n;
static void f() {
int cnt = 0;
for (int i = 2; i <= n; i++) {
if (!st[i]) primer[cnt++] = i;
//枚举i的质数倍
for (int j = 0; primer[j] <= n / i; j++) {
st[primer[j] * i] = true;
if (i % primer[j] == 0) break;
}
}
}
}
package 数学;
import java.util.Arrays;
import java.util.Scanner;
/**
* https://blog.csdn.net/tomjobs/article/details/104804802
* 区间筛法:改进筛法筛区间
*/
public class 质数距离 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
f(50000);
l = sc.nextInt();
r = sc.nextInt();
System.out.println(r);
Arrays.fill(st, false);
for (int i = 0; i < cnt; i++) {
int p = primer[i];
for (long j = Math.max(p * 2, (l + p - 1) / p * p); j <= r; j += p) {
st[(int) (j - l)] = true;
//下标很大,偏移量很小
}
}
cnt = 0;
for (int i = 0; i <= r - l; i++) {
if (!st[i] && i + l >= 2) primer[cnt++] = (int) (i + l);
}
if (cnt < 2) System.out.println("There are no adjacent primes.");
else {
int minp = 0, maxp = 0;
for (int i = 0; i + 1 < cnt; i++) {
int d = primer[i + 1] - primer[i];
if (d < primer[minp + 1] - primer[minp]) minp = i;
if (d > primer[maxp + 1] - primer[maxp]) maxp = i;
}
System.out.printf("%d,%d are closest, %d,%d are most distant.\n", primer[minp], primer[minp + 1], primer[maxp], primer[maxp + 1]);
}
}
}
static int cnt = 0;
static boolean[] st = new boolean[(int) 1e6+100];
static int[] primer = new int[(int) 1e5];
//筛出前根号n的素数,这些素数的倍数落在(l,r)之间就是合数,
// 而r-l距离很小,这样就可以统计出素数了
static void f(int n) {
Arrays.fill(st, false);
cnt = 0;
for (int i = 2; i <= n; i++) {
if (!st[i]) primer[cnt++] = i;
for (int j = 0; primer[j] * i <= n; j++) {
st[primer[j] * i] = true;
if (i % primer[j] == 0) break;
}
}
}
static long l, r;
}
package 数学;
/**
*
*/
public class 阶乘分解 {
public static void main(String[] args) {
}
}
......@@ -3,6 +3,7 @@ package dp;
import java.util.Arrays;
/**
* https://www.acwing.com/file_system/file/content/whole/index/content/521410/
* https://mp.weixin.qq.com/s?__biz=MzUyNjQxNjYyMg==&mid=2247486923&idx=2&sn=6c1c8aeb4db68522e67ddf8c1e933660&chksm=fa0e624acd79eb5cdb410808921609a830b9b9221e813e4eb89cf551ca48f317668d44b095d2&scene=21#wechat_redirect
* LeetCode 第 221 号问题:最大正方形。
* 在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册