Google Code Jam 2019 Round 1A 题解

A. Alien Rhyme

题意:

思路:将字符反向插入一颗Trie,然后自下而上的贪心即可,即先选后缀长的,再选后缀短的。

实现:

  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 const int maxlen = 50+1;
 38 const int N = 1000+1;
 39 const int maxn = N * maxlen;
 40 const int A = 26;
 41 int g[maxn][A], cnt[maxn], tot;
 42 inline int newnode()
 43 {
 44     memset(g[tot], 0, sizeof(g[tot]));
 45     cnt[tot] = 0;
 46     return tot++;
 47 }
 48 void init()
 49 {
 50     tot = 0;
 51     newnode();
 52 }
 53 char s[maxlen];
 54 void insert()
 55 {
 56     int len = strlen(s);
 57     int cur = 0;
 58     for (int i = len-1; i >= 0; --i)
 59     {
 60         int c = s[i] - 'A';
 61         if (g[cur][c] == 0) g[cur][c] = newnode();
 62         cur = g[cur][c];
 63         ++cnt[cur];
 64     }
 65 }
 66 int solve(int cur)
 67 {
 68     if (cnt[cur] == 1) return 0;
 69     int ret = 0;
 70     for (int c = 0; c < A; ++c)
 71         if (g[cur][c])
 72         {
 73             //cerr << "from " << cur << " via " << char('A'+c) << " to " << g[cur][c] << endl;
 74             ret += solve(g[cur][c]);
 75         }
 76     int tmp = cnt[cur] - ret;
 77     if (tmp >= 2) ret += 2;
 78     return ret;
 79 }
 80 int main()
 81 {
 82 //    ios::sync_with_stdio(false);
 83 //    cin.tie(0);
 84 //    int T; cin >> T;
 85     int T; scanf("%d", &T);
 86     for (int kase = 1; kase <= T; ++kase)
 87     {
 88         int n; scanf("%d", &n);
 89         init();
 90         for (int i = 0; i < n; ++i)
 91         {
 92             scanf("%s", s);
 93             insert();
 94         }
 95         printf("Case #%d: %d\n", kase, solve(0));
 96     }
 97 }
 98 /*
 99  1
100  10 5 5
101  101010101000010100101
102  0 2 4 6 8 13 15  18 20
103  */
View Code

 

B. Golf Gophers

题意:

思路:设所求的人数为TARGET。我们可以把18个计数器弱化为1个计数器,具体就是每个计数器的阈值Bi都设为同一个,计作MOD,这样我们每次询问之后,所有计数器被拨动之后值的和就等于 TARGET%MOD。这个看起来是不是很像中国剩余定理?发现小于18的质数刚好7个{2,3,5,7,11,13,17},而且每个质数的最高幂{16,9,5,7,11,13,17}的乘积大于1e6(TARGET的最大可能值),所以就迎刃而解了

实现:

  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 int T, N, M;
 40 vector<int> query(int mycnt, int myvalue, int judgecnt)
 41 {
 42     for (int i = 0; i < mycnt; ++i)
 43         printf("%d%c", myvalue, " \n"[i+1==mycnt]);
 44     fflush(stdout);
 45     vector<int> ret(judgecnt, 0);
 46     for (auto & e : ret)
 47         scanf("%d", &e);
 48     return ret;
 49 }
 50 vector<int> factor = {16, 9, 5, 7, 11, 13, 17};
 51 vector<int> inv;
 52 int all;
 53 ll power(ll base, ll p, ll mod)
 54 {
 55     ll ret = 1 % mod;
 56     while (p)
 57     {
 58         if (p&1) ret = ret * base % mod;
 59         base = base * base % mod;
 60         p >>= 1;
 61     }
 62     return ret;
 63 }
 64 ll inverse(ll base, ll mod)
 65 {
 66     return power(base, mod-2, mod);
 67 }
 68 void preprocess()
 69 {
 70     all = 1;
 71     for (auto e : factor) all *= e;
 72     for (auto e : factor)
 73     {
 74         int y = all/e;
 75         ll _inv = -1;
 76         for (int i = 1; i < e; ++i)
 77             if (1ll * i * y % e == 1)
 78             {
 79                 _inv = i;
 80                 break;
 81             }
 82         assert(_inv != -1);
 83         inv.pb(y * _inv);
 84     }
 85 }
 86 const int MILL = 18;
 87 int process(int factor)
 88 {
 89     auto response = query(MILL, factor, MILL);
 90     int ret = 0;
 91     for (auto e : response) (ret += e) %= factor;
 92     return factor;
 93 }
 94 
 95 void solve()
 96 {
 97     ll ret = 0;
 98     for (int i = 0; i < factor.size(); ++i)
 99     {
100         (ret += 1ll * process(factor[i]) * inv[i] % all) %= all;
101     }
102     auto tmp = query(1, ret, 1);
103     assert(tmp.size() == 1 && tmp.front() == 1);
104 }
105 int main()
106 {
107     preprocess();
108     scanf("%d %d %d", &T, &N, &M);
109     for (int kase = 1; kase <= T; ++kase)
110         solve();
111 }
View Code

 

C. Pylons

题意:

思路:比较明显的是在r或c比较大的时候,可以利用样例里的思路拓展一下(也许需要tweak一下奇偶性的问题)。r和c都比较小的时候可以利用和traveling salesman problem类似的方式打表(也可以暴搜)。应该是有比较规律性的解法,这里没有细想。

实现:写的太丑了就不贴了,而且我大约写了另外两个文件来生成数据/测试/打表。

posted @ 2019-04-13 12:03  大四开始ACM  阅读(992)  评论(0编辑  收藏  举报