题目在这里:https://code.google.com/codejam/contest/6224486/dashboard
有种资格赛一年比一年难的感觉,难道是我越来越弱了。。。。
A. Standing Ovation
注意到如果x是一个可行解的话,所有比x大的数都会是可行解,因此很自然的满足二分的要求。不过数据范围比较小,也可以从小到大进行暴力枚举,然后验证是否符合要求,找到的第一个数即为答案。
#include <bits/stdc++.h> #define FOR(i, n) for (int i = 0; i < n; ++i) using namespace std; int main() { int N, mx; string s; cin >> N; FOR(tt, N) { cin >> mx >> s; assert(s.size() == mx + 1); int res = 0; for (res = 0; res <= mx; ++res) { int val = res + (s[0] - '0'); bool ok = true; for (int i = 1; i <= mx; ++i) { if (val >= i) { val += s[i] - '0'; continue; } else { ok = false; break; } } if (ok) { cout << "Case #" << tt + 1 << ": " << res << endl; break; } } } return 0; }
B. Infinite House of Pancakes
这题用贪心来解,首先要明白:special minute排在前面所得到的解总不会比排在后面的得到的解差。原因很简单:special minute之后非空盘子的数目增多,每一分钟可以吃掉的蛋糕数也变多,更有利于尽快完成任务。
所以可以认为:先执行了x分钟的special minute操作,然后接下来全是吃蛋糕,花了y分钟,y肯定就等于最大的蛋糕体积。答案就应该是x + y
但是x和y的取值是多少呢?这个地方就需要一个枚举的过程来辅助,枚举y的值,对每一个y值,计算每一个蛋糕拆成不大于y的蛋糕所需要的时间,累加便得到x,最后取min(x + y)即可
#include <bits/stdc++.h> #define FOR(i, n) for (int i = 0; i < n; ++i) using namespace std; int main() { int N, D; vector<int> numbers; cin >> N; FOR(tt, N) { cin >> D; numbers.resize(D); FOR(i, D) cin >> numbers[i]; int res = 1005, mx = *max_element(numbers.begin(), numbers.end()); // enumerate maximum number for (int i = 1; i <= mx; ++i) { int cur = 0; FOR(j, numbers.size()) { if (numbers[j] % i == 0) cur += numbers[j] / i - 1; else cur += numbers[j] / i; } res = min(res, cur + i); } cout << "Case #" << tt + 1 << ": " << res << endl; } return 0; }
C. Dijkstra
跟图论毛线关系都没有。。google的人完全是标题党。。。
一个很自然的思路是把字符串构造出来,分别从左右两边进行扫描,但是字符串太长,内存和时间都不允许。假设a等于一个字符串运算的结果,那么a^4 = 1总成立,不管a的取值是什么,所以可以按照重复次数对4取模的余数进行分类,左右两侧只有4 * 4 = 16种可能的取值,对于每一种取值组合,只在一个字符串内部进行扫描,判断左侧能否计算出i,右侧能否计算出k。
#include <bits/stdc++.h> #define FOR(i, n) for (int i = 0; i < n; ++i) using namespace std; string multiply(const string& s1, const string& s2) { assert(s1.size() <= 2 && s2.size() <= 2); if (s1 == "1") return s2; if (s2 == "1") return s1; if (s1[0] == '-' && s2[0] == '-') return multiply(s1.substr(1, 1), s2.substr(1, 1)); if (s1[0] == '-') { string t = multiply(s1.substr(1, 1), s2); if (t[0] == '-') return t.substr(1, 1); else return "-" + t; } if (s2[0] == '-') { string t = multiply(s1, s2.substr(1, 1)); if (t[0] == '-') return t.substr(1, 1); else return "-" + t; } assert(s1.size() == 1 && s2.size() == 1); if (s1 == s2) return "-1"; if (s1 == "i" && s2 == "j") return "k"; if (s1 == "i" && s2 == "k") return "-j"; if (s1 == "j" && s2 == "k") return "i"; if (s1 == "j" && s2 == "i") return "-k"; if (s1 == "k" && s2 == "i") return "j"; if (s1 == "k" && s2 == "j") return "-i"; assert(false); return ""; } string spow(const string& number, long long p) { if (p % 4 == 0) return "1"; if (p % 4 == 2) return multiply(number, number); if (p % 4 == 1) return number; else return multiply(number, multiply(number, number)); } int main() { int T, len; long long repeat; string s; cin >> T; FOR(tt, T) { cout << "Case #" << tt + 1 << ": "; cin >> len >> repeat; cin >> s; assert(len == s.size()); string res = "1"; FOR(i, s.size()) res = multiply(res, s.substr(i, 1)); // a necessary condition if (spow(res, repeat) != "-1") { cout << "NO" << endl; continue; } bool solution = false; FOR(i, 4) { if (solution) break; string left = spow(res, i); bool ok = false; int lidx = -1; FOR(k, s.size()) { if (ok || left == "i" || left == "-i") { ok = true; break; } left = multiply(left, s.substr(k, 1)); if (left == "i" || left == "-i") { ok = true; lidx = k; break; } } if (!ok || lidx == s.size() - 1) continue; FOR(j, 4) { if (solution) break; string right = spow(res, j); ok = false; int ridx = -1; for (int k = s.size() - 1; k >= 0; --k) { if (ok || right == "k" || right == "-k") { ok = true; break; } right = multiply(s.substr(k, 1), right); if (right == "k" || right == "-k") { ok = true; ridx = k; break; } } if (!ok || ridx == 0) continue; int total = i + j; assert(lidx != -1 || ridx != -1); if (lidx == -1 && ridx != -1) ++total; else if (lidx != -1 && ridx == -1) ++total; else if (lidx < ridx) ++total; else if (lidx >= ridx) total += 2; if (repeat >= total) { solution = true; break; } } } if (solution) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }
D. Ominous Omino
这完全就是脑筋急转弯的题目。。。考的不是算法而是人的智商。。。
首先注意到,N >= 7是不可能有解的,题目中第二张图就说明了这个结论,中间那个空隙无论如何都是填充不进去的。
然后对N = 1, 2, 3, 4, 5, 6分别枚举,考虑哪些情况无解就可以了。N = 5的时候有一个不容易想的地方,就是5行3列的情形,
中间那个是不可能有解的,因为它把整个矩形分割成了两部分,上半部分不能够被5整除,无论怎么放都不行,囧。。。
import java.util.*; import java.io.*; /** * @author: kyc */ public class D { static int N, R, C; public static void main(String ... orange) throws Exception { Scanner input = new Scanner(System.in); int numCases = input.nextInt(); for (int n = 0; n < numCases; n++) { N = input.nextInt(); R = input.nextInt(); C = input.nextInt(); System.out.printf("Case #%d: %s\n", n + 1, good() ? "GABRIEL" : "RICHARD"); } } static boolean good() { if (R * C % N != 0) return false; if (N >= 7) return false; else if (N == 6) { if (Math.min(R, C) <= 3) return false; } else if (N == 5) { if (Math.min(R, C) <= 2 || Math.min(R, C) == 3 && Math.max(R, C) == 5) return false; } else if (N == 4) { if (Math.min(R, C) <= 2) return false; } else if (N == 3) { if (Math.min(R, C) <= 1) return false; } return true; } }