1. 程式人生 > >Google Code Jam 2019 Qualification

Google Code Jam 2019 Qualification

過程 sync ble .get down 實現 continue 矛盾 namespace

A. Foregone Solution

題意:給你一個大於1小於1e100的整數(至少有一個數位的值是4),讓你把它表示為兩個正整數的和,並且這兩個正整數的十進制表達中都不能包含數位4。保證有解

思路:每個數位可以獨立的解決。

實現:設最後答案的兩個數是a和b,然後把不是4的數位都分給a,把是4的數位拆成(1,3)或(2, 2) 分給a和b。因為題目保證至少存在一個數位位4,所以這樣分a和b一定都是正整數。

B. You Can Go Your Own Way

題意:在一個n*n的網格上,從左上角出發,只能向右或者向下走,經過2*n-2步到達右下角。題目給出了一個由Left(E,as in East)和Down(S,as in South)組成的路徑prod,要求你給出一個路徑dev,使得不存在在某一個點,dev和prod走了相同的方向。(即如果dev和prod同時經過了某個點,且dev走的下一步是E,那麽prod必須走S,以此類推)

思路:關於對角線反置一下prod就好了

實現:讀入prod,將E和S互換。

證明:通過上述構建方式得到dev,如果dev不合法,without the loss of generality,設第一次路徑重合的地方是(a,b)-> (a,b+1)。由於這條邊在dev中也存在,那麽(b,a)-> (b+1, a)這條邊在prod中也存在。我們不妨假設prod中,先走了(a,b)-> (a,b+1),後走了(b,a)-> (b+1, a),那麽易知 (b,a)這個點是(a,b)之後經過的。所以有

b > a 且 a > b。矛盾

C. Cryptopangrams

題意:出題人隨機選了26個不超過1e100的素數,按照從小到大排列,把每個素數分給起對應的字母,得到了一個由大寫字母到這26個素數的一個bijection。然後出題人通過這個bijection對一段message加密,加密過程為

(1)把每個字符替換成其對應的素數,得到一個長度和message相同的整數數列,計為v[]

(2)生成一個長度為n-1的數字序列a[],其中a[i] = v[i] * v[i+1]

保證26字符每個都至少在message裏出現一次。n不超過100,告訴你數列a[],讓你求出原文。

思路:觀察到,我們只要找出一個v[i],剩下的v[i]就可以通過某些a[x]和之前得到的v[y]作商得到。下面我們想怎麽樣可以找出一個v[i]。因為每個字符都出現一次,那麽在message中一定存在i使得message[i] != message[i+2](否則,message只會由至多兩種字符組成,因為奇數位都相同,偶數位也是),繼而得到v[i] != v[i+2] -> v[i] * v[i+1] != v[i+2] * v[i+1],即a[i] != a[i+1]。然後v[i+1] = gcd(a[i], a[i+1])。

實現:

技術分享圖片
 1 import java.io.*;
 2 import java.util.*;
 3 import java.text.*;
 4 import java.math.*;
 5 public class Solution
 6 {
 7     public static void main(String args[])
 8     {
 9         Scanner stdin = new Scanner(System.in);        
10         int T = stdin.nextInt();
11         for (int kase = 1; kase <= T; ++kase)
12             {
13                 System.out.print("Case #" + Integer.toString(kase) + ": ");
14                 BigInteger N = stdin.nextBigInteger();
15                 int n = stdin.nextInt();
16                 BigInteger[] cipher = new BigInteger[n];
17                 BigInteger[] original = new BigInteger[n+1];
18                 for (int i = 0; i < n; ++i)
19                     {
20                         cipher[i] = stdin.nextBigInteger();
21                         // System.out.println(cipher[i]);
22                     }
23                 int tar = 0;
24                 for (tar = 0; tar < n-1 && cipher[tar].equals(cipher[tar+1]); ++tar);
25                 original[tar+1] = cipher[tar].gcd(cipher[tar+1]);
26                 for (int i = tar; i >= 0; --i) original[i] = cipher[i].divide(original[i+1]);
27                 for (int i = tar+1; i < n; ++i)
28                     original[i+1] = cipher[i].divide(original[i]);
29                 TreeSet<BigInteger> set = new TreeSet<BigInteger>();
30                 for (int i = 0; i < n+1; ++i)
31                     set.add(original[i]);                
32                 TreeMap<BigInteger, Character> mapping = new TreeMap<BigInteger, Character>();
33                 assert(set.size() == 26);
34                 char base = ‘A‘;
35                 for (BigInteger code : set)
36                     {
37                         mapping.put(code, base);
38                         ++base;
39                     }
40                 for (int i = 0; i < n+1; ++i)
41                     System.out.print(mapping.get(original[i]));
42                 System.out.println();
43             }
44     }
45 };
View Code

D. Dat Bae

題意:交互題。大概就是,有N (<= 1024)個bit,裏面有B(<=min(N-1, 15))個bit是disabled的。每次你可以send一個長度為N的01串bits,judge會將bits中disabled的bit刪掉,返回給你這個長度為N-B的01串。下面要求你在不超過F(小 case F = 10, 大 case F = 5)次詢問中,測出哪些bit是disabled的。

思路:

(a) 小 case。比較容易猜出10和1024(2^10)之間的關系,可以二分區間解決(其實有點像自上而下建立線段樹)。首先,send一個前N/2個bit都是0,後面 (N+1)/2個bit都是1的詢問,得到judge的回復response後,數response中0的個數和1的個數(由於我們的詢問,0只能是前導0,1也只能是後綴1),這樣我們就知道前N/2個bit和剩下的bit各自有幾個bit是壞的,同時我們也知道前N/2個bit在response中對應的有效區間是哪一塊了。之後我們前N/2個bit和後面(N+1)/2個bit就不相關了,我們可以按照相似的步驟遞歸處理前半段和後半段,如果發現一整段都是壞的,我們就可以停止遞歸。這樣最差情況在10步內就可以求出所有的disabled bit。

(b) 大 case。其實小case做法的本質就是確定某個區間在response中對應的區間是什麽。我們發現,B不會超過15,那麽我們可以把N分成每MAGIC=16個一組,一共大約N/MAGIC組。在第一詢問的時候,第0組全填0,第1組全填1,以此類推,偶數組填0,奇數組填1。這樣會發現,在response中,一定有交替出現的N/MAGIC組連續的0和1,即我們可以直接確定每個組在response對應的區間。(其實MAGIC=15也可以,容易想但不太好解釋。)之後我們就可以確定若幹個(其實是不超過15個,但是這個數字對復雜度沒有影響)長度為MAGIC的包含disable bit的區間。之後我們就按照小case中的做法處理這些區間,需要的詢問數為log2(MAGIC) <= 4,加上我們第一次的詢問,一共不超過5次。

實現:

技術分享圖片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <iomanip>
  5 
  6 #include <vector>
  7 #include <cstring>
  8 #include <string>
  9 #include <queue>
 10 #include <deque>
 11 #include <stack>
 12 #include <map>
 13 #include <set>
 14 
 15 #include <utility>
 16 #include <list>
 17 
 18 #include <cmath>
 19 #include <algorithm>
 20 #include <cassert>
 21 #include <bitset>
 22 #include <complex>
 23 #include <climits>
 24 #include <functional>
 25 #include <unordered_set>
 26 #include <unordered_map>
 27 using namespace std;
 28 
 29 typedef long long ll;
 30 typedef pair<int, int> ii;
 31 typedef pair<ll, ll> l4;
 32 typedef pair<double, double> dd;
 33 #define mp make_pair
 34 #define pb push_back
 35 
 36 #define debug(x) cerr << #x << " = " << x << " "
 37 
 38 
 39 vector<int> ans;
 40 string rpc(const string &s)
 41 {
 42     cout << s << endl;
 43     fflush(stdout);
 44     string ret;
 45     cin >> ret;
 46     return ret;
 47 }
 48 const int MAGIC = 15;
 49 typedef pair<ii, ii> i4;
 50 string initial_query(int n)
 51 {
 52     string ret = "";
 53     for (int i = 0; i < n; ++i)
 54     {
 55         ret += 0 + (i/MAGIC%2);
 56     }
 57     return ret;
 58 }
 59 void deal(vector<i4> &to_push, int start, int expect_count, int start_ptr, int actual_count)
 60 {
 61     if (actual_count == expect_count) return;
 62     if (actual_count == 0)
 63     {
 64         for (int j = 0; j < expect_count; ++j) ans.pb(start+j);
 65         return;
 66     }
 67     to_push.pb(mp(mp(start,expect_count),mp(start_ptr,actual_count)));
 68 }
 69 vector<i4> initial_rpc(int n)
 70 {
 71     string response = rpc(initial_query(n));
 72     vector<i4> ret;
 73 
 74     for (int i = 0, ptr = 0; i * MAGIC < n; ++i)
 75     {
 76         const int expected = i&1;
 77         const int expected_count = min(MAGIC, n - i * MAGIC);
 78         int start_ptr = ptr;
 79         while (ptr < response.size()
 80                && ptr-start_ptr+1 <= expected_count
 81                && response[ptr] == 0+expected)
 82             ++ptr;
 83         deal(ret, i*MAGIC, expected_count, start_ptr, ptr-start_ptr);
 84         /*
 85         if (ptr - start_ptr == expected_count) continue;
 86         if (ptr == start_ptr)
 87         {
 88             for (int j = 0; j < expected_count; ++j) ans.pb(i*MAGIC+j);
 89             continue;
 90         }
 91         ret.pb(mp(mp(i*MAGIC, expected_count), mp(start_ptr, ptr-start_ptr)));
 92          */
 93     }
 94     return ret;
 95 }
 96 vector<i4> solve(int n, const vector<i4> &v)
 97 {
 98     string query = string(n, 1);
 99     for (auto e : v)
100     {
101         for (int i = 0; i < e.first.second/2; ++i)
102             query[e.first.first+i] = 0;
103     }
104     string response = rpc(query);
105     vector<i4> ret;
106     for (auto e : v)
107     {
108         int len = e.first.second/2;
109         int last_zero = -1;
110         for (int i = 0; i < e.second.second; ++i)
111             if (response[e.second.first+i] == 0) last_zero = i;
112         //for (int i = 0; i <= last_zero; ++i) assert(response[e.second.first+i] == ‘0‘);
113         //for (int i = last_zero+1; i < e.second.second; ++i) assert(response[e.second.first+i] == ‘1‘);
114         deal(ret, e.first.first, len, e.second.first, last_zero+1);
115         deal(ret, e.first.first+len, e.first.second-len, e.second.first+last_zero+1, e.second.second-last_zero-1);
116     }
117     return ret;
118 }
119 int main()
120 {
121     ios::sync_with_stdio(false);
122     cin.tie(0);
123     int T; cin >> T;
124     for (int kase = 1; kase <= T; ++kase)
125     {
126         int n, b, f;
127         cin >> n >> b >> f;
128         ans.clear();
129         auto v = initial_rpc(n);
130         while (f > 0 && !v.empty()) --f, v = solve(n, v);
131         assert(v.empty());
132         assert(ans.size() == b);
133         sort(ans.begin(), ans.end());
134         for (int i = 0; i < ans.size(); ++i)
135             cout << ans[i] << " ";
136         string return_code = rpc("");
137 
138     }
139 }
140 /*
141  1
142  10 5 5
143  101010101000010100101
144  0 2 4 6 8 13 15  18 20
145  */
View Code

Google Code Jam 2019 Qualification