2011-05-09
SRM 504 Div2
Easy (250) ComparerInator 比較専用言語
問題
- 特定の比較演算結果と一致しているなら、1または7を返す
- 1と7の両方を満たす場合は1を返す
- 1も7も満たさない場合は-1を返す
はまりポイント
- 解く速さ優先なら、まとめるよりもコピペして1つずつ確実に判定したほうがよさげ。
実装した内容
- 演算子毎にカウントする
- a < bの判断自体は共通なのでまとめる
- カウントの長さが配列の長さと一致したら、その演算子を満たしたとみなす
https://github.com/firewood/topcoder/blob/master/srm_5xx/srm_504/ComparerInator.cpp
Medium (500) MathContest 白黒ボール
問題
- シーケンシャルなキューに白または黒のボールが入っている
- キューから1つずつボールを取り出す
- 取り出したボールが白だったらキューの残りのボールの並びを反転する
- 取り出したボールが黒だったらキューの残りのボールの色を反転する
実装した内容
- 配列の先頭と最後にポインタを設定しておく
- 並びが反転したら、読むポインタを変更する
- 色が反転したら、判定する色を変更する
https://github.com/firewood/topcoder/blob/master/srm_5xx/srm_504/MathContest.cpp
Hard (1000) Algrid 色塗り
問題
- 白または黒のセルで構成されたグリッドがある
- 上の行から下の行に、左から右に向かって処理する
- ある位置の処理において、上の位置の内容に応じて下の位置を塗る、または交換する
はまりポイント
- 塗られた部分については、元データがどちらでもよいので、Bとみなす
- 塗られていない部分については、交換操作を考慮して、元データのどの場所から来ているのかという情報を保持する必要がある
実装した内容
- 塗るべきところを塗る
- 交換するところは、ポインタを交換する
- 塗った部分について、出力データと比較して、不一致なら失敗とする
- 塗った部分はどちらでもよいので、元データをBとする
- 塗っていない部分は、出力データからもってくる
https://github.com/firewood/topcoder/blob/master/srm_5xx/srm_504/Algrid.cpp
結果
今回は問題文が比較的わかりやすかった。
システムのエラーにより残念ながらnon-rated。
時間中にはEasyとMediumを回答し、のちほどチェックしたところEasyはミスっていてMediumはOKだった。
2011-04-17
SRM 503 Div2
Easy (250) ToastXRaspberry 奇抜なトースト
文章がわかりづらい。
- 一度に最大upper_limit層まで塗れる
- layer_count層を塗るための最小の塗りの回数
ってこれだけ?
class ToastXRaspberry {
public:
int apply(int upper_limit, int layer_count) {
return (layer_count + upper_limit - 1) / upper_limit;
}
};
Medium (500) ToastXToast ナイスなトースト
境界条件の理解に時間がかかった。場合わけすると-1と1と2しかない。
焼いた種類のパンについて、必ずovertoastedとundertoastedが存在する、という文章を制約条件だと読んでいなかったため、システムテストに落ちた。汚かったので整理して書き直した。
#include <algorithm>
#include <vector>
using namespace std;
class ToastXToast {
public:
int bake(vector <int> undertoasted, vector <int> overtoasted) {
sort(undertoasted.begin(), undertoasted.end());
sort(overtoasted.begin(), overtoasted.end());
if (undertoasted.size() < 1 || overtoasted.size() < 1) {
return -1;
}
if (*undertoasted.rbegin() >= *overtoasted.rbegin() ) {
return -1;
}
if (*undertoasted.begin() >= *overtoasted.begin() ) {
return -1;
}
if (*undertoasted.rbegin() < *overtoasted.begin()) {
return 1;
}
return 2;
}
};
Hard (900) KingdomXCitiesandVillagesAnother 村を町につなぐ
孤立している村をなくせ。町または、町につながっている村とつなぐための道路を建設せよ。建設すべき道路の最小の合計値を求めよ。
残り15分くらいしかなく、テストのみ書いて終了。終了後、解いた人のソースを見て理解。
- 村のうち、最小の長さで町に接続できる村を見つける。
- 村と町を接続して、距離の合計値に加算する。
- その村を村のリストから削除して、町のリストに追加する。
#include <math.h>
#include <list>
#include <vector>
using namespace std;
struct XY {
int x;
int y;
};
typedef vector<int> VI;
typedef list<XY> LXY;
class KingdomXCitiesandVillagesAnother {
public:
double determineLength(vector <int> cityX, vector <int> cityY, vector <int> villageX, vector <int> villageY) {
LXY cities, villages;
VI::const_iterator x, y;
for (x = cityX.begin(), y = cityY.begin(); x != cityX.end(); ++x, ++y) {
XY city = {*x, *y};
cities.push_back(city);
}
for (x = villageX.begin(), y = villageY.begin(); x != villageX.end(); ++x, ++y) {
XY village = {*x, *y};
villages.push_back(village);
}
double total = 0.0;
while (villages.size() > 0) {
double distance = 0.0;
LXY::iterator it = findNearestVillage(cities, villages, distance);
cities.push_back(*it);
villages.erase(it);
total += distance;
}
return total;
}
static LXY::iterator findNearestVillage(const LXY &cities, LXY &villages, double &distance) {
LXY::iterator nearest = villages.end();
LXY::iterator village;
for (village = villages.begin(); village != villages.end(); ++village) {
LXY::const_iterator city;
for (city = cities.begin(); city != cities.end(); ++city) {
double d = getDistance(*city, *village);
if (nearest == villages.end() || d < distance) {
nearest = village;
distance = d;
}
}
}
return nearest;
}
static double getDistance(const XY &a, const XY &b) {
double x = a.x - b.x;
double y = a.y - b.y;
return sqrt(x * x + y * y);
}
};
結果
ox- 200.98+231.06*0
Easyのみシステムテストに通ってratingが932。Mediumが時間内にきちんと解けるようになりたい。
Hardは30分くらいで解くのはまだきつい感じ。
2011-04-15
SRM 502 Div2
Easy (250) TheProgrammingContestDivTwo プログラミングコンテスト
N個のタスクが与えられる。それぞれ解くのにrequiredTime[i]の時間かかる。
解くとスコアが1増えてペナルティが経過時間tだけ増える。
T分の間に、スコアの最大値と、そのときのペナルティを返す。
requiredTimeを昇順にソートして加える。
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
typedef vector <int> VI;
class TheProgrammingContestDivTwo {
public:
VI find(int T, VI requiredTime) {
sort(requiredTime.begin(), requiredTime.end());
int past = 0;
int solved = 0;
int penalty = 0;
VI::const_iterator it;
for (it = requiredTime.begin(); it != requiredTime.end(); ++it) {
past += *it;
if (past > T) {
break;
}
++solved;
penalty += past;
}
VI r;
r.push_back(solved);
r.push_back(penalty);
return r;
}
};
Medium (500) TheLotteryBothDivs 当たりくじ
9桁の数字のくじがあり、当たりくじのsuffixが与えられるとき、当たる確率を求める。
suffixをprefixと考えても同じなので、suffix文字列を逆順にすることで、suffixをprefixに変換した。
prefixの小さい桁から順番に確率を加えていく。
桁数の小さいprefixは桁数の大きいprefixを含むので、より大きいprefixの中に処理中のprefixを含むものがあれば、無効にする。
#include <algorithm>
#include <string>
#include <vector>
#include <set>
using namespace std;
typedef vector<string> StringVector;
typedef set<string> StringSet;
class TheLotteryBothDivs {
public:
double find(vector <string> goodSuffixes) {
StringSet seq[10]; // use 1 to 9
StringVector::const_iterator it;
for (it = goodSuffixes.begin(); it != goodSuffixes.end(); ++it) {
if (it->length() >= 1 && it->length() <= 9) {
string s = *it;
reverse(s.begin(), s.end());
seq[it->length()].insert(s);
}
}
double result = 0.0;
double rate = 0.1;
for (int i = 1; i <= 9; ++i) {
StringSet::const_iterator it;
for (it = seq[i].begin(); it != seq[i].end(); ++it) {
result += rate;
for (int j = i + 1; j <= 9; ++j) {
StringSet::iterator temp;
while (true) {
temp = seq[j].lower_bound(*it);
if (temp == seq[j].end() || strncmp(it->c_str(), temp->c_str(), it->length()) != 0) {
break;
}
seq[j].erase(temp);
}
}
}
rate /= 10.0;
}
return result;
}
};
Hard (1000) TheCowDivTwo 逃げた牛のカウント
0からN-1まで番号がついたN匹の牛のうち、K匹が逃げた。
逃げた牛の番号を合計するとNで割り切れるとき、可能な牛の組み合わせの場合の数を求めよ。
なんかもやもやしてわからなかったので、ぐぐって解法を調べた。
nまでの番号がついた牛が(1~47)匹逃げたときの場合の数を求めておき、(n+1)までの番号がついた牛が逃げたときの場合の数を、そこからの差分で求めていく。
面倒だったのでstaticの二次元配列。
#include <string>
#include <vector>
using namespace std;
class TheCowDivTwo {
public:
int find(int N, int K) {
static int current[47][1024];
memset(current, 0, sizeof(current));
current[0][0] = 1;
for (int n = 0; n < N; ++n) {
static int prev[47][1024];
memcpy(prev, current, sizeof(current));
for (int p = 1; p <= K; ++p) {
for (int m = 0; m < N; ++m) {
int mod = (m + n) % N;
current[p][mod] += prev[p - 1][m];
current[p][mod] %= 1000000007;
}
}
}
int result = current[K][0];
return result;
}
};