Google Code Jam 2015资格赛

题目在这里: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;
    }
}


不管怎么说,资格赛肯定是水过去了。。。。神啊,求google code jam的T-shirt!



你可能感兴趣的:(Google Code Jam 2015资格赛)