Technocup 2019 - Elimination Round 2
http://codeforces.com/contest/1031
(如果感觉一道题对于自己是有难度的,不要后退,懂0%的时候敲一遍,边敲边想,懂30%的时候敲一遍,边敲边想,懂60%的时候敲一遍,边敲边想,(真实情况是你其实根本不用敲那么多遍……),然后,这道题你就差不多可以拿下了ψ(`∇´)ψ)
(IO模板在最后的蛋里)
A. Golden Plate
n*m矩形,最外圈为第一圈,间隔着选k个圈,问总共占多少给格子
每圈贡献=2n‘+2m'-4,圈圈长宽以-4递减下去
public static void main(String[] args) { IO io=new IO(); int n=io.nextInt(),m=io.nextInt(),k=io.nextInt(); long ans=0; while (k-->0){ ans+=2*n+2*m-4; n-=4;m-=4; } io.println(ans); }
B. Curiosity Has No Limits
给你长度为n-1的两个数列,问是否存在长度为n的数列t,满足ai=ti|ti+1&&bi=ti&ti+1,三个数列的元素都属于[0,3]
元素太少了,一开始想直接打表,但i、j到底哪个先哪个后不知道,所以从找规律入手
1 System.out.println(i+" "+j+" "+(i|j)+" "+(i&j)); 2 //对应ti、ti+1、ai、bi 3 0 0 0 0 4 0 1 1 0 5 0 2 2 0 6 0 3 3 0 7 1 0 1 0 8 1 1 1 1 9 1 2 3 0 10 1 3 3 1 11 2 0 2 0 12 2 1 3 0 13 2 2 2 2 14 2 3 3 2 15 3 0 3 0 16 3 1 3 1 17 3 2 3 2 18 3 3 3 3
发现ti + ti+1==ai + bi,可以枚举t[0],看是否得到合法的数列t
1 public static void main(String[] args) { 2 IO io = new IO(); 3 int n = io.nextInt(); 4 int[] a = new int[n]; 5 int[] b = new int[n]; 6 int[] t = new int[n]; 7 for (int i = 0; i < n - 1; i++) a[i] = io.nextInt(); 8 for (int i = 0; i < n - 1; i++) b[i] = io.nextInt(); 9 OUT: 10 for (int i = 0; i < 4; i++) { 11 t[0] = i; 12 for (int j = 1; j < n; j++) { 13 t[j] = a[j - 1] + b[j - 1] - t[j - 1]; 14 if ((t[j] | t[j - 1]) != a[j - 1] || 15 (t[j] & t[j - 1]) != b[j - 1]) continue OUT; 16 } 17 io.println("Yes"); 18 for (int j = 0; j < n; j++) io.print(t[j] + " "); 19 return; 20 } 21 io.println("No"); 22 }
C. Cram Time
给你两个数a、b,输出元素总个数最多的且累加和分别不超过a、b的两组数,其中每个数只能用一次
关键点在于当n是1+2+……+n<=a+b的最大的n时,1到n的所有数都一定选得上,只要对其中一个数从大到小取就可以保证
1 public static void main(String[] args) { 2 IO io = new IO(); 3 int a = io.nextInt(), b = io.nextInt(), cnt = 0, n = 0; 4 long l = 1, r = a + b, mid; 5 while (l <= r) { 6 mid = (l + r) / 2; 7 if (a + b < (mid + 1) * mid / 2) { 8 r = mid - 1; 9 } else { 10 l = mid + 1; 11 n = (int) mid; 12 } 13 } 14 int[] vis = new int[n + 1]; 15 for (int i = n; i >= 1; i--) 16 if (a >= i) { 17 a -= i; 18 cnt++; 19 vis[i] = 1; 20 } 21 io.println(cnt); 22 for (int i = 1; i <= n; i++) if (vis[i] == 1) io.print(i + " "); 23 io.println("\n" + (n - cnt)); 24 for (int i = 1; i <= n; i++) if (vis[i] == 0) io.print(i + " "); 25 io.close(); 26 }
D. Minimum path
有一个由小写字母填满的n*n矩阵,你可以改变不超过k个字母,使从(1,1)到(n,n)的字典序最小,你只能往右走或往下走
k全部用来把前面非‘a'字符换成’a'。搜索从用完k后获得长度最长‘a'串开始。ans[i]表示答案的第i个字符,对于每个ans[i],搜索所有i可能的位置,取其最小值。因为对于每个特定的长度i,其末位置不会和长度i-1的末位置重叠(如下图),所以长度i得到的末尾点j,i-j+1,vis[j][i-j+1]表示为长度为i时该点是否可达。
0 1 2 3 4 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8
1 public static void main(String[] args) { 2 IO io = new IO(); 3 int n = io.nextInt(), k = io.nextInt(); 4 5 int[][] a = new int[c][c]; 6 int[][] dp = new int[c][c]; 7 int[][] vis = new int[c][c]; 8 int[] ans = new int[c * 2]; 9 10 for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) a[i][j] = io.nextChar(); 11 int len = 0; 12 //【初始化一定不要偷懒】 13 vis[1][1] = 1; 14 for (int i = 1; i <= n; i++) 15 for (int j = 1; j <= n; j++) { 16 //【这里也是一样,不要贪图代码短】 17 if (i == 1 && j == 1) dp[1][1] = 0; 18 else if (i == 1) dp[1][j] = dp[1][j - 1]; 19 else if (j == 1) dp[i][1] = dp[i - 1][1]; 20 else dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]); 21 if (a[i][j] != 'a') dp[i][j]++; 22 if (dp[i][j] <= k) { 23 vis[i + 1][j] = vis[i][j + 1] = 1; 24 len = Math.max(i + j - 1, len); 25 } 26 } 27 Arrays.fill(ans, 'z'); 28 Arrays.fill(ans, 1, len + 1, 'a'); 29 for (int i = len + 1; i <= 2 * n - 1; i++) { 30 for (int j = 1; j <= n; j++) 31 if (1 <= i - j + 1 && i - j + 1 <= n && vis[j][i - j + 1] == 1) 32 ans[i] = Math.min(ans[i], a[j][i - j + 1]); 33 //因为最小点可能不止一个,所以不能只记录一个点 34 for (int j = 1; j <= n; j++) 35 if (1 <= i - j + 1 && i - j + 1 <= n && vis[j][i - j + 1] == 1 36 && a[j][i - j + 1] == ans[i]) 37 vis[j + 1][i - j + 1] = vis[j][i - j + 2] = 1; 38 } 39 for (int i = 1; i <= 2 * n - 1; i++) io.print((char) ans[i]); 40 }
E. Triple Flips
给你长度为n的01串,你可以对其进行不超过n/3+12次操作将其变成全0串,该操作为选三个间隔相等的数将其翻转(0->1,1->0),如果存在解,请打印出所有操作数字的下标
关键思想是每次保证最左边或最右边的三个数为0,字符串过小时枚举每一种情况。
1 private static final int c = (int) (1e5 + 10); 2 static IO io = new IO(); 3 static int n; 4 static int[] a = new int[c]; 5 //一边操作一边记录 6 static ArrayList<int[]> ans = new ArrayList<>(); 7 8 static void solve0(int l, int r) { 9 ArrayList<int[]> p = new ArrayList<>(); 10 int[] t = new int[c]; 11 int a1, a2; 12 13 for (int i = l; i <= r; i++) for (int j = i + 2; j <= r; j += 2) p.add(new int[]{i, j}); 14 OUT: 15 for (int i = 0; i < 1 << p.size(); i++) { 16 System.arraycopy(a, l, t, l, r - l + 1); 17 for (int j = 0; j < p.size(); j++) 18 if ((i >> j & 1) == 1) { 19 a1 = p.get(j)[0]; 20 a2 = p.get(j)[1]; 21 t[a1] ^= 1; 22 t[a2] ^= 1; 23 t[a1 + a2 >> 1] ^= 1; 24 } 25 for (int j = l; j <= r; j++) if (t[j] == 1) continue OUT; 26 for (int j = 0; j < p.size(); j++) 27 if ((i >> j & 1) == 1) ans.add(p.get(j)); 28 29 io.println("YES"); 30 io.println(ans.size()); 31 for (int[] v : ans) io.println(v[0] + " " + (v[0] + v[1] >> 1) + " " + v[1]); 32 return; 33 } 34 io.println("NO"); 35 } 36 37 //坚定不移保证左三或右三全为0 38 static void solve(int l, int r) { 39 //flip需要长度至少为7 40 if (r - l + 1 < 7) { 41 while (l > 1 && r - l + 1 < 8) l--; 42 while (r < n && r - l + 1 < 8) r++; 43 solve0(l, r); 44 return; 45 } 46 if (a[l] == 0) { 47 solve(l + 1, r); 48 return; 49 } 50 if (a[r] == 0) { 51 solve(l, r - 1); 52 return; 53 } 54 //111…… 55 if (a[l + 1] == 1 && a[l + 2] == 1) { 56 flip_add(l, l + 2); 57 solve(l + 3, r); 58 return; 59 } 60 //……111 61 if (a[r - 1] == 1 && a[r - 2] == 1) { 62 flip_add(r - 2, r); 63 solve(l, r - 3); 64 return; 65 } 66 //101…… 67 if (a[l] == 1 && a[l + 2] == 1) { 68 flip_add(l, l + 4); 69 solve(l + 3, r); 70 return; 71 } 72 //……101 73 if (a[r - 2] == 1 && a[r] == 1) { 74 flip_add(r - 4, r); 75 solve(l, r - 3); 76 return; 77 } 78 //100……翻转分别为l、l+2、l+4,目标是结果为000 79 if (a[l + 1] == 0 && a[l + 2] == 0) { 80 flip_add(l, l + 6); 81 solve(l + 3, r); 82 return; 83 } 84 //……001 85 if (a[r - 1] == 0 && a[r - 2] == 0) { 86 flip_add(r - 6, r); 87 solve(l, r - 3); 88 return; 89 } 90 //110……和……011 91 if ((r - l + 1) % 2 == 1) { 92 flip_add(l, r); 93 flip_add(l + 1, r - 1); 94 solve(l + 3, r - 3); 95 } else { 96 flip_add(l, r - 1); 97 flip_add(l + 1, r); 98 solve(l + 3, r - 3); 99 } 100 } 101 102 public static void main(String[] args) { 103 n = io.nextInt(); 104 for (int i = 1; i <= n; i++) a[i] = io.nextInt(); 105 solve(1, n); 106 }111 112 //0变1,1变0 113 static void flip_add(int l, int r) { 114 a[l] ^= 1; 115 a[r] ^= 1; 116 a[l + r >> 1] ^= 1; 117 ans.add(new int[]{l, r}); 118 }
F. Familiar Operations
有正整数a、b以及两种操作:1、对其中一个数乘以某个素数,2、对其中一个数除以其素因子,问让两个数因子数相同的最小操作是多少。
1 public static void main(String[] args) { 2 int[] prim = new int[c]; 3 int[][][] dp = new int[289][31][1201]; 4 HashSet<ArrayList<Integer>> s = new HashSet<>(); 5 ArrayList<Integer> t = new ArrayList<>(); 6 ArrayList<ArrayList<Integer>> qt = new ArrayList<>(); 7 ArrayList<Integer>[] v = new ArrayList[c]; 8 for (int i = 1; i < c; i++) v[i] = new ArrayList<>(7); 9 Arrays.fill(prim, 1); 10 11 for (int i = 2; i < c; i++) 12 if (prim[i] == 1) for (int j = 1; i * j < c; j++) { 13 int x = j; 14 int p = 2; 15 while (x % i == 0) { 16 x /= i; 17 p++; 18 } 19 v[i * j].add(p); 20 prim[i * j] = 0; 21 } 22 for (int i = 1; i < c; i++) while (v[i].size() < 7) v[i].add(1); 23 for (int i = 1; i < c; i++) { 24 Collections.sort(v[i]); 25 s.add(v[i]); 26 } 27 qt.addAll(s); 28 for (int i = 0; i < qt.size(); i++) 29 for (int j = 0; j <= 30; j++) Arrays.fill(dp[i][j], 999); 30 for (int y = 0; y < qt.size(); y++) { 31 t.clear(); 32 for (int i = 0; i < 7; i++) t.add(qt.get(y).get(i)); 33 while (t.size() < 30) t.add(1); 34 dp[y][0][1] = 0; 35 for (int i = 0; i < 30; i++) { 36 for (int j = 1; j <= 1200; j++) { 37 if (dp[y][i][j] < 999) for (int l = 1; j * l <= 1200; l++) 38 dp[y][i + 1][j * l] = Math.min(dp[y][i + 1][j * l], 39 dp[y][i][j] + Math.abs(t.get(i) - l)); 40 } 41 } 42 } 43 44 IO io = new IO(); 45 int n = io.nextInt(); 46 while (n-- > 0) { 47 int p1 = qt.indexOf(v[io.nextInt()]), g1 = qt.indexOf(v[io.nextInt()]); 48 int ans = 9000; 49 for (int j = 1; j <= 1200; j++) ans = Math.min(ans, dp[p1][30][j] + dp[g1][30][j]); 50 io.println(ans); 51 } 52 }
彩蛋(/≧▽≦)/丢~快接~