TZOJ 挑战题库随机训练10(JAVA)
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }