Technocup 2019

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 - 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     }

彩蛋(/≧▽≦)/丢~快接~

View Code
原文地址:https://www.cnblogs.com/towerbird/p/9933746.html