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
沒做出來,感覺沒什麼頭緒,待我研究了大神的代碼以後補上

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