TZOJ 挑战题库随机训练10(JAVA)

点击题号跳转

A5985 B1792 C5644 D4038 E3229

F3322 G3614 H2824 I4286 J6225

A.矩形嵌套回到顶部

题意

n个矩形嵌套,跟E题类似,求最多嵌套,n<=1000

题解

这个题因为比较的是点对,所以可以先排序,使得第一维有序,然后只需要求出第二维的最长上升子序列,复杂度O(nlogn)

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6 
 7         Solution solver = new Solution();
 8         solver.solve();
 9     }
10 
11 }
12 
13 class Solution {
14 
15     private final int N = 1005;
16 
17     private int[] dp = new int[N << 1];
18     private List<Node> list = new ArrayList<>();
19 
20     class Node {
21         int l, r;
22         Node(int l, int r) {
23             this.l = l;
24             this.r = r;
25         }
26     }
27 
28     public void solve() {
29         Scanner sc = new Scanner(System.in);
30         int t = sc.nextInt();
31         while (sc.hasNext()) {
32             int n = sc.nextInt();
33             list.clear();
34             for (int i = 0; i < n; i++) {
35                 int l = sc.nextInt();
36                 int r = sc.nextInt();
37                 list.add(new Node(l, r));
38                 list.add(new Node(r, l));
39                 dp[i] = dp[n + i] = 0;
40             }
41 
42             Collections.sort(list, (o1, o2) -> {
43                 if (o1.l > o2.l) return 1;
44                 else if (o1.l == o2.l) {
45                     if (o1.r > o2.r) return 1;
46                     else if (o1.r == o2.r) return 0;
47                 }
48                 return -1;
49             });
50 
51             //list.stream().forEach((node) -> System.out.println(node.l + " " + node.r));
52 
53             int maxx = 0;
54             for (int i = 0; i < n << 1; i++) {
55                 dp[i] = 1;
56                 for (int j = 0; j < i; j++) {
57                     if (list.get(i).l > list.get(j).l && list.get(i).r > list.get(j).r) {
58                         dp[i] = Math.max(dp[i], dp[j] + 1);
59                     }
60                 }
61                 maxx = Math.max(maxx, dp[i]);
62             }
63 
64             System.out.println(maxx);
65         }
66     }
67 }
A

B.Introspective Caching回到顶部

题意

背景:类似于操作系统的请求分页(分段)过程

快速缓冲区大小c,n个不同的程序,q次请求访问快速缓冲区的程序,问最少需要多少次把程序调入快速缓冲区,q<=10^5

题解

这样想,需要删除的元素肯定是要最远(值r)才有用的,如果删的不是最远的(值v),那么就会在r之前把v再调入快速缓冲区,如果删了最远的,这次操作就可以省略

每个程序维护一个nxt[i],nxt[i]代表值为i的下一个位置,用TreeSet维护,复杂度O(nlogn)

PS:TreeSet自定义类需要实现Comparable,然后重载compareTo方法,TreeSet底层红黑树,会自动排序,排序会调用compareTo方法

PS:TreeSet.contains会调用compareTo方法用0来判断相同

PS:compareTo值为正表示A>B,值为0表示A=B,值为负表示A<B

PS:一开始contains方法没起作用调了好久,后来发现判断相同需要返回0,因为自动排序正交换0和负不交换,就忽略了0的处理

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13 
14     class Node implements Comparable<Node> {
15 
16         int i, val;
17 
18         Node(int i, int val) {
19             this.i = i;
20             this.val = val;
21         }
22 
23         //@Override
24         public int compareTo(Node o) {
25             if (i < o.i) return 1;
26             else if (i > o.i) return -1;
27             else return 0;
28         }
29     }
30 
31     public void solve() {
32         Scanner sc = new Scanner(System.in);
33         int c = sc.nextInt();
34         int n = sc.nextInt();
35         int q = sc.nextInt();
36         int[] a = new int[q + 5];
37         int[] nxt = new int[q + 5];
38         int[] ha = new int[n + 5];
39         for (int i = 1; i <= q; i++) a[i] = sc.nextInt();
40         for (int i = q; i >= 1; i--) {
41             if (ha[a[i]] == 0) nxt[i] = q + 1;
42             else nxt[i] = ha[a[i]];
43             ha[a[i]] = i;
44         }
45         TreeSet<Node> treeSet = new TreeSet<>();
46 //        Node node1 = new Node(1, 2);
47 //        treeSet.add(node1);
48 //        treeSet.add(new Node(2, 3));
49 //        treeSet.add(new Node(1, 3));
50 //        treeSet.add(new Node(5, 7));
51 //        treeSet.stream().forEach((node) -> System.out.println(node.i + " " + node.val));
52 //        System.out.println(treeSet.contains(node1));
53 
54         int ans = 0;
55         for (int i = 1; i <= q; i++) {
56             Node node = new Node(i, a[i]);
57             if (treeSet.contains(node)) {
58                 treeSet.remove(node);
59                 treeSet.add(new Node(nxt[i], a[i]));
60             } else {
61                 if (treeSet.size() == c) treeSet.pollFirst();
62                 treeSet.add(new Node(nxt[i], a[i]));
63                 ans++;
64             }
65         }
66         System.out.println(ans);
67     }
68 
69 }
B

C.C实验:复读机回到顶部

题意

输入一行文本s,输出s,在输出s wsl,要求用给定函数实现

题解

char* p = (char*)malloc(105*sizeof(char));复杂度O(105)

PS:可能有空格,需要gets读入

代码

1 char *GetText(){
2    char *p=(char*)malloc(105*sizeof(char));
3    gets(p);
4    return p;
5 }
C

D.Robot Navigation回到顶部

题意

机器人从NWES出发到X,指令1往当前方向走x步,指令2右转,指令3左转,问到X的最少指令和方案数,n,m<=100

题解

最短路计数,dis[i][j][k]代表走到(i,j)方向是k的最短距离,cal表示方案数

指令1相当于判断当前方向,然后走,如果为*就break

指令2相当于+1%4,指令3相当于(-1+4)%4,复杂度O(4nm)

PS:一直以为距离相同也要放进队列重新更新,然后就mle了,后来发现不需要,感谢黄bob

——相当于自带了一个bfs,保证了最短,无权的直接考虑层,有权的相当于用权值维护了一个层

——dij可以理解为堆优化的bfs,spfa是队列优化的,如果层数过多spfa炸了,但是dij活着

——但是如果出现负权,dij考权值搜索肯定炸了,但是spfa活着

PS:为了不出现重复代码,可以把相同方法抽取出一个函数

PS:测试了一下LinkedLists比ConcurrentLinkedQueue慢,所以最好还是用后面一个

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13 
14     private final int N = 105;
15     private final int INF = 1000000000;
16     private final long P = 1000000;
17 
18     private Queue<Integer> qx = new LinkedList<Integer>();
19     private Queue<Integer> qy = new LinkedList<Integer>();
20     private Queue<Integer> qdir = new LinkedList<Integer>();
21     private char[][] g = new char[N][N];
22     private int[][][] dis = new int[N][N][4];
23     private long[][][] cal = new long[N][N][4];
24 
25     public void solve() {
26         Scanner sc = new Scanner(System.in);
27         while (sc.hasNext()) {
28             int n = sc.nextInt();
29             int m = sc.nextInt();
30             if (n == 0 && m == 0) break;
31             int sx = 0, sy = 0, sdir = 0, ex = 0, ey = 0;
32 
33             for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) for (int k = 0; k < 4; k++) {
34                 dis[i][j][k] = INF;
35                 cal[i][j][k] = 0;
36             }
37 
38             for (int i = 0; i < n; i++) {
39                 g[i] = sc.next().toCharArray();
40                 for (int j = 0; j < m; j++) {
41                     if (g[i][j] == 'N' || g[i][j] == 'E' || g[i][j] == 'S' || g[i][j] == 'W') {
42                         sx = i; sy = j;
43                         if (g[i][j] == 'N') sdir = 0;
44                         else if (g[i][j] == 'E') sdir = 1;
45                         else if (g[i][j] == 'S') sdir = 2;
46                         else if (g[i][j] == 'W') sdir = 3;
47                     } else if (g[i][j] == 'X') {
48                         ex = i; ey = j;
49                     }
50                 }
51             }
52 
53             bfs(n, m, sx, sy, sdir, ex, ey);
54         }
55     }
56 
57     private void bfs(int n, int m, int sx, int sy, int sdir, int ex, int ey) {
58         qx.clear(); qy.clear(); qdir.clear();
59         qx.add(sx); qy.add(sy); qdir.add(sdir);
60         dis[sx][sy][sdir] = 0; cal[sx][sy][sdir] = 1;
61         while (!qx.isEmpty()) {
62             int ux = qx.poll(), uy = qy.poll(), udir = qdir.poll();
63             //System.out.println("ux:" + ux + " uy:" + uy + " udir:" + udir + " dis:" + dis[ux][uy][udir]);
64             // 上,右,下,左
65             if (udir == 0) for (int i = ux - 1; i >= 0; i--) if (g[i][uy] == '*') break; else update(ux, uy, udir, i, uy, udir);
66             else if (udir == 1) for (int i = uy + 1; i < m; i++) if (g[ux][i] == '*') break; else update(ux, uy, udir, ux, i, udir);
67             else if (udir == 2) for (int i = ux + 1; i < n; i++) if (g[i][uy] == '*') break; else update(ux, uy, udir, i, uy, udir);
68             else if (udir == 3) for (int i = uy - 1; i >= 0; i--) if (g[ux][i] == '*') break; else update(ux, uy, udir, ux, i, udir);
69             // 右转
70             update(ux, uy, udir, ux, uy, (udir + 1) % 4);
71             // 左转
72             update(ux, uy, udir, ux, uy, (udir + 3) % 4);
73         }
74         long minnDis = INF, ans = 0;
75         for (int i = 0; i < 4; i++) if (minnDis > dis[ex][ey][i]) minnDis = dis[ex][ey][i];
76         for (int i = 0; i < 4; i++) if (minnDis == dis[ex][ey][i]) ans = (ans + cal[ex][ey][i]) % P;
77         System.out.println((minnDis == INF ? 0 : minnDis) + " " + ans);
78     }
79 
80     // 更新答案
81     private void update(int ux, int uy, int udir, int vx, int vy, int vdir) {
82         if (dis[ux][uy][udir] + 1 < dis[vx][vy][vdir]) {
83             dis[vx][vy][vdir] = dis[ux][uy][udir] + 1;
84             cal[vx][vy][vdir] = cal[ux][uy][udir];
85             qx.add(vx); qy.add(vy); qdir.add(vdir);
86         } else if (dis[ux][uy][udir] + 1 == dis[vx][vy][vdir]) {
87             cal[vx][vy][vdir] = (cal[vx][vy][vdir] + cal[ux][uy][udir]) % P;
88         }
89     }
90 }
D

E.Rectangles回到顶部

题意

n个矩形嵌套,跟A题类似,求最多嵌套,n<=2000

题解

求最长路,分析一下可以知道是单向边和无环图,那么最长路就是放负权值的最短路,复杂度O(n^2)

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13 
14     private final int N = 1005;
15 
16     private List<List<Integer>> list = new ArrayList<>();
17     private int[] d = new int[N];
18     private Point[] p1 = new Point[N];
19     private Point[] p2 = new Point[N];
20     private Queue<Integer> q = new LinkedList<>();
21     private int n;
22 
23     class Point {
24         int x, y;
25         Point(int x, int y) {
26             this.x = x;
27             this.y = y;
28         }
29     }
30 
31     public void solve() {
32         Scanner sc = new Scanner(System.in);
33         while (sc.hasNext()) {
34             n = sc.nextInt();
35             if (n == 0) break;
36             list.clear();
37             list.add(new ArrayList<>());
38             for (int i = 1;i <= n; i++) {
39                 p1[i] = new Point(sc.nextInt(), sc.nextInt());
40                 p2[i] = new Point(sc.nextInt(), sc.nextInt());
41                 list.add(new ArrayList<>());
42             }
43 
44             for (int i = 1;i <= n; i++) {
45                 for (int j = 1; j <= n; j++) {
46                     if (check(i, j))
47                         list.get(i).add(j);
48                 }
49             }
50             for (int i = 1; i <= n; i++) list.get(0).add(i);
51 
52             System.out.println(dij());
53         }
54     }
55 
56     private boolean check(int i, int j) {
57         return p2[i].x < p1[j].x && p2[i].y < p1[j].y;
58     }
59 
60     private int dij() {
61         d[0] = 0;
62         for (int i = 1; i <= n; i++) d[i] = 1000000000;
63         q.clear(); q.add(0);
64         while (!q.isEmpty()) {
65             int u = q.poll();
66             for (int i = 0; i < list.get(u).size(); i++) {
67                 int v = list.get(u).get(i);
68                 if (d[v] > d[u] - 1) {
69                     q.add(v);
70                     d[v] = d[u] - 1;
71                 }
72             }
73         }
74         int ans = 0;
75         for (int i = 1; i <= n; i++) ans = Math.max(ans, -d[i]);
76         return ans;
77     }
78 }
E

F.悼念512汶川大地震遇难同胞――选拔志愿者回到顶部

题意

AB轮流捐钱,单次不超过m,总共捐到n结束,A开始

题解

简单博弈,如果n%(m+1)==0,由于A最多拿m,比如A拿了a,那么B只需要拿m+1-a,就可以让B赢,复杂度O(1)

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13 
14     public void solve() {
15         Scanner sc = new Scanner(System.in);
16         int c = sc.nextInt();
17         for (int i = 0; i < c; i++) {
18             int n = sc.nextInt();
19             int m = sc.nextInt();
20             if (n % (m + 1) == 0) System.out.println("Rabbit");
21             else System.out.println("Grass");
22         }
23     }
24     
25 }
F

G.小强的Linux回到顶部

题意

给一个图,每个点需要时间,有依赖关系,问安装完n个点需要最少时间,n<=1000

题解

拓扑排序,首先取出时间最少的,把度数为0的所有点减掉最少时间,如果安装完就把这个点从图上去掉,并更新度数,复杂度O(n^2)

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13 
14     private final int N = 1005;
15 
16     private int[] d = new int[N];
17     private int[] t = new int[N];
18     private int[] vec = new int[N];
19     private boolean[][] G = new boolean[N][N];
20     private boolean[] vis = new boolean[N];
21 
22     public void solve() {
23         Scanner sc = new Scanner(System.in);
24         int n = sc.nextInt();
25         for (int i = 1; i <= n; i++) t[i] = sc.nextInt();
26         int m = sc.nextInt();
27         for (int i = 1; i <= m; i++) {
28             int u = sc.nextInt();
29             int v = sc.nextInt();
30             if (!G[v][u]) {
31                 G[v][u] = true;
32                 d[u]++;
33             }
34         }
35 
36         int sum = 0;
37         for (int i = 1; i <= n; i++) {
38             int minn = 1000000000;
39             int tot = 0;
40             for (int j = 1; j <= n; j++) {
41                 if (!vis[j] && d[j] == 0) {
42                     vec[tot++] = j;
43                     minn = Math.min(minn, t[j]);
44                 }
45             }
46             if (minn == 1000000000) break;
47             for (int j = 0; j < tot; j++) {
48                 t[vec[j]] -= minn;
49                 if (t[vec[j]] == 0) {
50                     vis[vec[j]] = true;
51                     for (int k = 1; k <= n; k++) {
52                         if (!vis[k] && G[vec[j]][k]) {
53                             G[vec[j]][k] = false;
54                             d[k]--;
55                         }
56                     }
57                 }
58             }
59             sum += minn;
60         }
61 
62         System.out.println(sum);
63     }
64 }
G

H.Unique Snowflakes回到顶部

题意

n个点,问最长连续的一段不存在重复的数字,n<=10^6

题解

这样想,如果a[l]=a[r],那么只需要去掉a[l],l+1往后还是满足的,复杂度O(n)

PS:题意get错误2次,晕了

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13 
14     private HashMap<Integer, Integer> hashMap = new HashMap<>();
15 
16     public void solve() {
17 
18         Scanner sc = new Scanner(System.in);
19         int t = sc.nextInt();
20         for (int i = 0; i < t; i++) {
21             hashMap.clear();
22             int n = sc.nextInt();
23             int maxl = 0, maxx = 0;
24             for (int j = 0; j < n; j++) {
25                 int x = sc.nextInt();
26                 if (hashMap.containsKey(x))
27                     maxl = Math.max(maxl, hashMap.get(x) + 1);
28                 hashMap.put(x, j);
29                 maxx = Math.max(maxx, j - maxl + 1);
30             }
31             System.out.println(maxx);
32         }
33     }
34 }
H

I.Draw Something Cheat回到顶部

题意

n个长度12的大写串,问每个串都有的字母(会重复),n<=20

题解

每个串处理一个a[26],答案就是min(a[26]),复杂度O(n^2)

PS:第一次没有get到重复这个坑

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13 
14     public void solve() {
15 
16         Scanner sc = new Scanner(System.in);
17         int t = sc.nextInt();
18         for (int i = 0; i < t; i++) {
19             int n = sc.nextInt();
20             int[] sum1 = new int[26];
21             for (int j = 0; j < n; j++) {
22                 String s = sc.next();
23                 int[] sum2 = new int[26];
24                 for (int k = 0; k < s.length(); k++) {
25                     if (j == 0) sum1[s.charAt(k) - 'A']++;
26                     else sum2[s.charAt(k) - 'A']++;
27                 }
28                 if (j != 0) {
29                     for (int k = 0; k < 26; k++)
30                         sum1[k] = Math.min(sum1[k], sum2[k]);
31                 }
32             }
33             for (int j = 0; j < 26; j++)
34                 for (int k = 0; k < sum1[j]; k++)
35                     System.out.print((char) (j + 'A'));
36             System.out.println();
37         }
38     }
39 }
I

J.教堂回到顶部

题意

n*m个点,8个方向,距离1或sqrt(2),问走过每个点再回到起点的最短路

题解

如果n=1或m=1,那么就是走过去再走回来

如果n为奇m为奇,那么需要走一个斜

其余情况直接一次性走完

代码

 1 import java.util.*;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         Solution solver = new Solution();
 7         solver.solve();
 8     }
 9 
10 }
11 
12 class Solution {
13     
14     public void solve() {
15         Scanner sc = new Scanner(System.in);
16         while (sc.hasNext()) {
17             double m = sc.nextDouble();
18             double n = sc.nextDouble();
19             if (m == 1) System.out.println(String.format("%.2f", (n - 1) * 2));
20             else if (n == 1) System.out.println(String.format("%.2f", (m - 1) * 2));
21             else if (n % 2 == 1 && m % 2 == 1) System.out.println(String.format("%.2f", n * m - 1 + Math.sqrt(2)));
22             else System.out.println(String.format("%.2f", n * m));
23         }
24     }
25 }
J
原文地址:https://www.cnblogs.com/taozi1115402474/p/12771593.html