Google APAC Round D题解

来源:互联网 发布:模拟炒股 app 知乎 编辑:程序博客网 时间:2024/06/07 04:42

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.141592653589793inline 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.141592653589793inline 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
没做出来,感觉没什么头绪,待我研究了大神的代码以后补上

0 0
原创粉丝点击