Google APAC 2016 University Graduates Test Round D解题报告

我过了AB两题,C的大数据挂了,D的大数据没有提交,61分滚粗。。。

这里写图片描述

A. Dynamic Grid

这个非常简单啦。。每一次查询就对网格做一遍广搜,判断有多少连通分量;每一次查询就直接在二维数组上修改。判断连通分量个数用并查集也行,都不难。

#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
int g[105][105];
const int dir_x[] = {1, -1, 0, 0};
const int dir_y[] = {0, 0, 1, -1};
int bfs(int row, int col) {
    vector<vector<bool> > visited(row, vector<bool>(col, false));
    int ret = 0;
    FOR(i, row) FOR(j, col) {
        if (g[i][j] == 1 && !visited[i][j]) {
            ++ret;
            queue<pii> q;
            q.push({i, j});
            visited[i][j] = true;
            while (!q.empty()) {
                pii tp = q.front(); q.pop();
                int r = tp.first, c = tp.second;
                FOR(k, 4) {
                    int nr = r + dir_x[k], nc = c + dir_y[k];
                    if (nr < 0 || nr >= row || nc < 0 || nc >= col || g[nr][nc] == 0 || visited[nr][nc]) continue;
                    q.push({nr, nc});
                    visited[nr][nc] = true;
                }
            }
        }
    }
    return ret;
}
void solve() {
    int row, col, N;
    cin >> row >> col;
    FOR(i, row) {
        string s;
        cin >> s;
        FOR(j, col) g[i][j] = s[j] - '0';
    }
    cin >> N;
    char type;
    int r, c, z;
    FOR(i, N) {
        cin >> type;
        if (type == 'M') {
            cin >> r >> c >> z;
            g[r][c] = z;
        }
        else {
            assert(type == 'Q');
            printf("%d\n", bfs(row, col));
        }
    }
    return;
}
int main() {
    int TestCase;
    cin >> TestCase;
    FOR(caseID, TestCase) {
        cout << "Case #" << caseID + 1 << ":" << endl;
        solve();
    }
    return 0;
}

B. gBalloon

大意就是在所有的气球位置移动总和不超过Q的约束下,最快能多长时间全部运动到原点。考虑对最短时间t进行二分查找,如果t是一个可行解,那么就更新上界,否则更新下界。

那么怎么判断t是不是一个可行解呢?首先,气球之间是独立的,每个气球要想消耗最少的能量,肯定是要找距离当前位置最近的并且能卡进t的目标位置,这算是一种贪心策略。最后累加所有气球消耗的能量,如果超过Q则t为不可行解。

#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
void solve() {
    int N, M, Q;
    cin >> N >> M >> Q;
    vector<int> v(M);
    FOR(i, M) cin >> v[i];
    vector<int> h(N), p(N);
    FOR(i, N) { cin >> p[i] >> h[i]; }
    double l = 0, r = 1e6;
    while (r - l > 1e-6) {
        double mid = (l + r) / 2.0;
        int cur = 0;
        bool ff = true;
        FOR(i, N) {
            bool ok = false;
            if (p[i] == 0) continue;
            FOR(d, M) {
                int h1 = h[i] - d, h2 = h[i] + d;
                if (h1 >= 0 && v[h1] * p[i] < 0 && mid >= -1.0 * (double)p[i] / v[h1]) {
                    cur += d;
                    ok = true;
                    break;
                }
                if (h2 < M && v[h2] * p[i] < 0 && mid >= -1.0 * (double)p[i] / v[h2]) {
                    cur += d;
                    ok = true;
                    break;
                }
            }
            if (!ok || cur > Q) { ff = false; break; }
        }
        if (mid > 1e5 && !ff) {
            cout << "IMPOSSIBLE" << endl;
            return;
        }
        if (!ff) l = mid;
        else r = mid;
    }
    cout << ceil(l) << endl;
    return;
}
int main() {
    int TestCase;
    cin >> TestCase;
    FOR(caseID, TestCase) {
        cout << "Case #" << caseID + 1 << ": ";
        solve();
    }
    return 0;
}

C.IP Address Summarization

大意就是给一些ip段,把它们排序并且合并。并不涉及什么算法,也不难,就是实现起来比较繁琐,我比赛的时候写错了合并条件,大数据挂了。。。ip最好还是用32位数来表示,后续的各种判断都可以用位操作来实现,合并的条件有两个:

1.两个子网的prefix长度应该是相同的。
2.两个子网归一化之后只有prefix中最低位不同。

#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
struct Node {
    vector<ll> ip;
    ll cnt, rep;
    Node() {
        ip.resize(4);
    }
    void norm() {
        ll rem = cnt;
        rep = 0;
        FOR(i, 4) {
            if (rem >= 8) {
                rem -= 8;
            }
            else if (rem == 0) {
                ip[i] = 0;
            }
            else {
                ll del = 8 - rem;
                ll tt = ~((1 << del) - 1);
                ip[i] = (tt & ip[i]);
                rem = 0;
            }
            rep += ip[i] * (1 << (24 - 8 * i));
        }
    }
    ll mx() {
        return rep + ((1ll << (32 - cnt)) - 1);
    }
    ll mn() { return rep; }
};
bool cmp(const Node& a, const Node& b) {
    FOR(i, 4) {
        if (a.ip[i] < b.ip[i]) return true;
        else if (a.ip[i] > b.ip[i]) return false;
    }
    return a.cnt < b.cnt;
}
bool check(Node& a, Node& b) {
    return (a.mx() >= b.mx() && a.mn() <= b.mn());
}
void solve() {
    ll N;
    cin >> N;
    vector<Node> arr(N);
    FOR(i, N) {
        char tmp;
        FOR(j, 4) {
            cin >> arr[i].ip[j] >> tmp;
        }
        cin >> arr[i].cnt;
        arr[i].norm();
    }
    sort(arr.begin(), arr.end(), cmp);
    ll ptr = 0;
    vector<Node> res;
    while (ptr < N) {
        ll i = ptr + 1;
        while (i < N && check(arr[ptr], arr[i])) ++i;
        res.push_back(arr[ptr]);
        ptr = i;
    }
    vector<Node> ans;
    while (true) {
        ans.clear();
        ans.push_back(res[0]);
        int ptr = 1;
        while (ptr < (int)res.size()) {
            if (res[ptr].cnt == res[ptr - 1].cnt && res[ptr - 1].mx() + 1 == res[ptr].mn()) {
                ll tmp = (1ll << (32 - res[ptr - 1].cnt));
                if (res[ptr - 1].mn() & tmp) {
                    ans.push_back(res[ptr++]);
                    continue;
                }
                --ans.back().cnt; ans.back().norm();
                if (ptr + 1 < (int)res.size()) ans.push_back(res[ptr + 1]);
                ptr += 2;
            }
            else {
                ans.push_back(res[ptr]);
                ++ptr;
            }
        }
        sort(ans.begin(), ans.end(), cmp);
        if (ans.size() == res.size()) break;
        res = ans;
    }
    arr = ans;
    FOR(ptr, arr.size()) {
        cout << arr[ptr].ip[0] << "." << arr[ptr].ip[1] << "."
            << arr[ptr].ip[2] << "." << arr[ptr].ip[3]
            << "/" << arr[ptr].cnt << endl;
    }
    return;
}
int main() {
    ll TestCase;
    cin >> TestCase;
    FOR(caseID, TestCase) {
        cout << "Case #" << caseID + 1 << ":" << endl;
        solve();
    }
    return 0;
}

D. Virtual Rabbit

大意是喂兔子,但是长时间不喂兔子就会挂掉,人在上班和睡觉期间不能喂,问要保持兔子D天之后还活着,最少喂多少次。

对于小数据的话,可以一步步模拟,那在什么时候喂才能保证次数最少呢?用反证法可以证明应该贪心,在保证兔子不饿死的前提下尽可能晚得喂。如果找不出这样的时间点,那么兔子必然饿死。。。

对于大数据,一步一步模拟肯定要跪,一个key insight在于一天只有8万多秒,在喂了一定次数之后肯定会形成周期,以后的模式都是重复的。

我比赛的时候就是想到以上部分,小数据AC,大数据不晓得为什么总是偶尔会多算了1天。

坑就坑在边界上,最后一个周期最后一次喂是有可能不必要的,因为D天之后就不需要管它的死活了。。。所以就最后一个周期换成一步步模拟。

#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const ll MOD = 24 * 60 * 60;
ll get() {
    ll ret = 0, val;
    char cc;
    cin >> val >> cc;
    ret += val * 60 * 60;
    cin >> val >> cc;
    ret += val * 60;
    cin >> val;
    ret += val;
    return ret;
}
void solve() {
    ll G = get(), W = get(), H = get(), B = get(), X = get();
    --W; --B;
    ll D, cur = 0;
    cin >> D;
    D = D * MOD;
    map<ll, ll> mp;
    ll step = 1, res = 0;
    bool first = true;
    vector<ll> arr(MOD), pos(MOD, -1), ss(MOD);
    FOR(i, MOD) {
        if (i >= G && i <= W) arr[i] = i;
        else if (i >= H && i <= B) arr[i] = i;
        else if (i > W && i < H) arr[i] = W;
        else if (i < G) arr[i] = B;
        else if (i > B) arr[i] = B;
    }
    while (true) {
        if (cur + X >= D) {
            break;
        }
        ll up = cur + X;
        ll feed = arr[up % MOD] + up / MOD * MOD;
        if (feed > up) {
            feed -= MOD;
            assert(feed <= up);
        }
        if (feed < 0 || feed <= cur) {
            cout << -1 << endl;
            return;
        }
        ll rem = feed % MOD;
        if (first && pos[rem] != -1) {
            first = false;
            ll len = feed - pos[rem], diff = step - mp[rem];
            ll num = (D - feed) / len;
            if (num == 0) {
                cur = feed;
                ++res;
                continue;
            }
            --num;
            res += num * diff;
            cur = feed + num * len;
            ++res;
        }
        else {
            pos[rem] = feed;
            ss[step] = feed;
            mp[rem] = step++;
            cur = feed;
            ++res;
        }
    }
    printf("%lld\n", res);
}
int main() {
    int TestCase;
    cin >> TestCase;
    FOR(caseID, TestCase) {
        cout << "Case #" << caseID + 1 << ": ";
        solve();
    }
    return 0;
}

总体上,这次题目有一点风格不一样,都是考智商和代码能力的。。。根本不是考算法。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值