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