Google APAC Round D题解

Problem A. Dynamic Grid
最基础的搜索,我用DFS做的,标记棋盘上每一个位置初始化为未搜索,遍历整个棋盘,如果遇到1且以前从没搜索到的话就从该点开始不停搜索,直到搜完,复杂度O(m*n)

代码

int m, n;
int q;
char b[110][110];
bool flag[110][110];
bool valid(int x ,int y)
{
    if(x < 0 || x >= m)
        return false;
    if(y < 0 || y >= n)
        return false;
    if(flag[x][y] == 1)
        return false;
    if(b[x][y] != '1')
        return false;
    return true;
}
void DFS(int x ,int y)
{
    flag[x][y] = 1;
    if(valid(x - 1, y))
        DFS(x - 1, y);
    if(valid(x + 1, y))
        DFS(x + 1, y);
    if(valid(x, y - 1))
        DFS(x, y -1);
    if(valid(x, y + 1))
        DFS(x, y + 1);
}
int solve()
{
    ZERO(flag);
    int count = 0;
    FOR(i,0,m)
    FOR(j,0,n)
    {
        if(b[i][j] == '1' && flag[i][j] == false)
        {
            DFS(i,j);
            count++;
        }
    }
    return count;
}
int main(){
    int Tcase;
    cin >> Tcase;

    FOR(hh,0,Tcase)
    {
        cin >> m >> n;
        FOR(i,0,m)
        FOR(j,0,n)
        cin >> b[i][j];
        cin >> q;
        cout << "Case #" << hh + 1 << ":" << endl;
        char ops;
        FOR(i,0,q)
        {
            cin >> ops;
            if(ops == 'Q')
                cout << solve() << endl;
            else
            {
                int x ,y;
                char val;
                cin >> x >> y >> val;
                b[x][y] = val;
            }
        }
    }

    return 0;
}

Problem B. gBalloon
很有意思的题目,首先考虑不可能的情况:
1.如果风向和距离的乘积为正数或者0(距离不为0),那么一定需要移动这个气球(称之为坏球),记下所需要的最小的消耗,如果所有坏球所需最小消耗的和大于q,那么不可能。
2.考虑如果需要移动气球,那么肯定是在时刻0的时候移动,我们用set维护一个3-element entry记录(当前气球标号,该球消耗的能量,到达0位置所需要的时间),并按最后一项的值从大向小排序。初始化时所有好球消耗的能量为0,时间根据dis/v向上取整。所有坏球计算所需最小的消耗和时间。每次从set中拿出第一位的项(时间最长),因为是它限制了最后到达的时间,给他能量看能否快过第二项,如果在当前能量+之前消耗的 可以保证他快过第二项,那么更新该项并且重新插入,同时更新剩余的能量。如果不能的话则循环结束,将所有的剩余能量尝试更新最开始的项,返回该项所需的时间。
因为每次消耗的q会最少增加1,所以总得复杂度是O(q * m * logn)

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}

int m, n;
int q;
int speed[1100];
pair<int,int> pos[110];

set<pair<int,int>,greater<pair<int,int> > > uset;
int calc(int p, int s)
{
    if(p * s >= 0)
        return INT_MAX;
    int t = p / s;
    if(t * s == p)
        return abs(t);
    else
        return abs(t) + 1;
}
int solve()
{
    int sum = 0;
    int flag[110];
    int energy[110];
    ZERO(energy);
    ZERO(flag);
    FOR(i,0,n)
    {
        if(pos[i].first == 0)
            continue;
        int p = pos[i].first;
        int h = pos[i].second;
        if(speed[h] * p == 0 || speed[h] * p > 0)
        {
            flag[i] = 1;
        }
        else
        {
            int t = p / speed[h];
            if(t * speed[h] == p)
                uset.insert(MP(abs(t),i));
            else
                uset.insert(MP(abs(t) + 1, i));
        }
    }
    int eng = 0;
    FOR(i,0,n)
    {
        if(!flag[i])
            continue;
        int p = pos[i].first;
        int h = pos[i].second;
        int MIN = q + 1;
        int index = -1;
        for(int j = 0; j < m; j++)
        {
            if(speed[j] * p < 0)
            {
                if(abs(j - h) < MIN)
                {
                    MIN = abs(j - h);
                    index = j;
                }
            }
        }
        if(index == -1)
            return -1;
        int t = p / speed[index];
        if(speed[index] * t == p)
            uset.insert(MP(abs(t), i));
        else
            uset.insert(MP(abs(t) + 1, i));
        flag[i] = MIN;
        energy[i] = MIN;
        eng += MIN;
    }
    if(eng > q)
        return -1;
    int remain = q - eng;
    while(remain > 0)
    {
        pair<int,int> slow = *(uset.begin());

        uset.erase(uset.begin());
        int limit = slow.first;
        if(uset.size())
            limit = uset.begin()->first;
        int ii = slow.second;
        int p = pos[ii].first;
        int h = pos[ii].second;
        remain += energy[ii];
        int index=  -1;
        int MIN = m + 1;
        int T = -1;
        for(int i = max(0, h - remain); i <= min(m - 1, h + remain); i++)
        {
            int tt = calc(p, speed[i]);

            if(tt < limit)
            {
                if(abs(i - h) < MIN)
                {
                    MIN = abs(i - h);
                    index = i;
                    T = tt;
                }
            }
        }

        if(index == -1 || remain < MIN)
        {
            uset.insert(slow);
            break;
        }
        energy[ii] = MIN;
        remain -= MIN;
        uset.insert(MP(T,ii));
    }
    int ii = uset.begin()->second;
    int tt = uset.begin()->first;
    int p = pos[ii].first;
    int h = pos[ii].second;


    for(int i = max(0, h - remain); i <= min(m - 1, h + remain); i++)
    {
        int t = calc(p, speed[i]);
        tt = min(tt,t);
    }


    return tt;

}
int main(){
    int Tcase;
    cin >> Tcase;

    FOR(hh,0,Tcase)
    {
        cin >> n >> m >> q;
        FOR(i,0,m)
        cin >> speed[i];
        FOR(i,0,n)
        cin >> pos[i].first >> pos[i].second;
        cout << "Case #" << hh + 1 << ": ";
        uset.clear();
        int res = solve();
        if(res != -1)
            cout << res << endl;
        else
            cout << "IMPOSSIBLE" << endl;
    }

    return 0;
}

Problem C. IP Address Summarization
这题当时卡了挺长时间,题意就是求最小的能表示当前网段的一个集合,因为比如1.0.0.0/9和1.128.0.0/9是可以合写成1.0.0.0/8的。对于斜杠后面的数我称它为掩码最低位。声明32个hashset,对于每个IP,先将其标准化后(和掩码&一下),然后转化为long long(高低位要分清楚,我是按照题意直接记录的,即1.0.0.0为00000001.24个0),因为32位数最高不超过2^32-1。根据掩码最低位的不同insert到不同的hashset里,这样先去重,然后从第32个hashset开始遍历所有的值,如果对第i个hashset的第j个值,设为val,如果val在第i位(从高向低)为1,那么看一下是否val去掉该位的值(val-(1<<(32-i))也在该hashset中,如果在的话就向前一个hashset中插入(val-(1<<(32-i)),当前hashset的不急着删除,反正下一步也会删除掉。
接下来就是去掉重合的subnet,仍旧从第32个hashset开始,对于每一项,如果一个一个去掉2进制中得1之后,所得到的值在之前的某个hashset中出现,则说明前面的subnet可以覆盖当前的,删掉即可。
复杂度为O(32 * 32 * n)
这题本身不难,我写的可能复杂了很多,主要是当时index从0或者从1开始理解起来很混乱,想清楚了以后实现还是很简单,位操作还是能解决很多问题的

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}

int n;
unordered_set<LL> uset[33];

string conv(LL val)
{
    vector<int> res(4);
    for(int i = 3; i >= 0 ; i--)
    {
        res[i] = val % 256;
        val /= 256;
    }
    string r;
    FOR(i,0,res.size())
    {
        r += to_string(res[i]);
        r.PB('.');
    }
    r.pop_back();
    return r;
}
vector<int> split(string s)
{
    int pos2 = s.find('.');
    int pos1 = 0;
    vector<string> res;
    while(pos2 != -1)
    {
        res.PB(s.substr(pos1, pos2 - pos1));
        pos1 = pos2 + 1;
        pos2 = s.find('.', pos1 );
    }
    if(pos1 != s.size())
        res.PB(s.substr(pos1));
    vector<int> ans;
    FOR(i,0,res.size())
    ans.PB(stoi(res[i]));
    return ans;
}
void clearPos(LL &val, LL base)
{
    if((val & base) == 0)
        return;
    val -= base;
}

int main(){
    int Tcase;
    cin >> Tcase;

    FOR(hh,0,Tcase)
    {
        FOR(i,0,33)
        uset[i].clear();
        cin >> n;
        FOR(i,0,n)
        {
            string s;
            cin >> s;
            int pos = s.find('/');
            int val = stoi(s.substr(pos + 1));
            vector<int> temp = split(s.substr(0,pos));
            LL tmp = 0;
            LL base = 1;
            for(int j = 3; j >= 0; j--)
            {
                tmp += base * temp[j];
                base *= 256;
            }
            //cout << conv(tmp) << endl;
            base = 1LL <<(32 -val);
            base /= 2;
            for(int j = val + 1; j <= 32; j++,base /= 2)
            {
                clearPos(tmp,base);
            }
            uset[val].insert(tmp);
        }
        LL base = 1;
        for(int i = 32; i >= 1; i--, base *= 2)
        {
            ITE(j,uset[i])
            {
                LL val = *j;
                if((val & base) != 0)
                {
                    LL val2 = val - base;
                    if(uset[i].count(val2) == 1)
                        uset[i- 1].insert(val2);
                }
                else
                {
                    LL val2 = val | base;
                    if(uset[i].count(val2) == 1)
                        uset[i- 1].insert(val);
                }
            }
        }
        base = 1;
        for(int i = 32; i >= 1; i--, base *= 2)
        {
            vector<LL> E;
            ITE(j,uset[i])
            {
                LL tmpBase = base;
                LL val = *j;
                clearPos(val, tmpBase);
                tmpBase *= 2;
                bool flag=  false;
                for(int k = i - 1; k >= 0; k--, tmpBase *= 2)
                {
                    if(uset[k].count(val) == 1)
                    {
                        flag = true;
                        break;
                    }
                    clearPos(val, tmpBase);
                }
                if(flag)
                    E.PB(*j);
            }
            FOR(j,0,E.size())
            uset[i].erase(E[j]);
        }
        set<pair<LL,int> > ans;
        for(int i = 32; i >= 1; i--, base *= 2)
        {
            ITE(j,uset[i])
            {
                ans.insert(MP(*j,i));
            }
        }
        cout << "Case #" << hh + 1 << ":" << endl;
        ITE(i,ans)
        cout << conv(i->first) << "/" << i->second << endl;

        // cout << solve() << endl;
    }

    return 0;
}

Problem D. Virtual Rabbit
没做出来,感觉没什么头绪,待我研究了大神的代码以后补上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章