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 */
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 }
C. Pylons
题意:
思路:比较明显的是在r或c比较大的时候,可以利用样例里的思路拓展一下(也许需要tweak一下奇偶性的问题)。r和c都比较小的时候可以利用和traveling salesman problem类似的方式打表(也可以暴搜)。应该是有比较规律性的解法,这里没有细想。
实现:写的太丑了就不贴了,而且我大约写了另外两个文件来生成数据/测试/打表。