SRM320 div2
easy
//やるだけ. //きわめて簡単なコード { int len = s.length(); s += '0'; //番兵.a-zとはちがう要素なので、最後に必ず条件分岐が真になる. int div = 0; //sumはかならずszに等しい.ならば分割数だけを調べればいいじゃないか. for(int i = 0; i < len; i++) { if(s[i] != s[i+1]) { div++; } } return 1.0*len/div; }
medium
いろいろと厄介な問題.
大小を比較するだけでいいので、
(1:[!]のかず(階乗の数ということにする)が等しいときに根の大小を比べる)
2:xの階乗の数、根の数がyよりもともに大きい(あるいは等しい)時、あきらかにx>yが成立する.
//問題は階乗の計算.
関数を作ってやると、例えば、456!とかを一気に計算してしまうとどんな整数の型でもoverflowを起こすので、一回一回計算するごとに常に2)の確認をする。
あと、0!は1なのでそこだけ注意.
string compare(string x, string y) { vector<string> num(2); num[0] = x; num[1] = y; //LL edit[2]にした方がいいかも。 int edit[2]; int fact[2]; //根と階乗の数 //Parse for(int i = 0; i < 2; i++) { int pos = num[i].find('!'); if(pos == string::npos) fact[i] = 0; //string::nposの処理系依存性の問題より場合分けが必要となる.( Topcoderでは[string::npos=-1] ) else {fact[i] = num[i].length()-pos;} num[i] = num[i].substr(0, pos); sscanf(num[i].c_str(), "%d", &edit[i]); } bool flag = true; //x > y //calculate while(1) { if(fact[0] == fact[1]) { if(edit[0] == edit[1]) { return "x=y"; } else { //ここは必要.9999999!! > 10000000!!とかだと次の作業にいって、edit[1] = 10000000*9999999;でoverflowする可能性あり. flag = (edit[0] > edit[1]); break; } } //fact[0] == fact[1]が真になることはない。階乗の数の大きい方を計算する. int mimz = (fact[0] > fact[1]) ? 0 : 1; fact[mimz]--; bool ok = false; //0!の場合の考慮 if(edit[mimz] == 0) { edit[mimz] = 1; continue; } //初期値:i=edit[mimz] ではない。 for(int i = edit[mimz]-1; i >= 1; i--) { edit[mimz] *= i; if(edit[mimz] > edit[1-mimz]) { ok = true; break; } } if(ok) { flag = (mimz) ? false : true; break; } } return (flag) ? "x>y" : "x<y"; }
//parseの所を極力みじかくするならこういうコードでもよい。 int pos = remove(num[i].begin(), num[i].end(), '!') - num[i].begin(); //これなら、string::nposの処理系依存の問題を避けられる. fact[i] = num[i].length()-pos; sscanf(num[i].substr(0, pos).c_str(), "%d", &edit[i]);
あるいは、
fact[i] = count(num[i].begin(), num[i].end(), '!'); sscanf(num[i].substr(0, num[i].length()-fact[i]).c_str(), "%d", &edit[i]);
difficult
終点のまわりに昇順にソートする。あとはmap構造を使う。
01234567890123456789 ----- 0.3 ----- 0.4 ----- 0.2 ----------0.4 -------0.3 とかのとき(既に終点のまわりに昇順ソートしてる) prev = 0; table[0] = 0.3; table[5] = 0.3; prev = 5; table[5] = 0.4; table[7] = 0.4; prev = 7; table[7] = 0.3+0.2; //table[0]+0.2; table[10] = 0.5 prev = 10; table[10] = max(0.4, 0.5); table[12] = 0.5; prev = 12; table[12] = max(0.3+0.4, 0.3+0.3); //max(table[0]+0.3, table[5]+0.4); table[14] = 0.7; -->ans = 0.7となる。 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ---------------------------------------------------> 0.3 0.4 0.5 0.5 0.7 0.7 //みたいになる。
vector<Line>ではなくて、vector< vector<int> >を使うとソート用のclassを用意しなくていいが、arr[0], arr[1], arr[2]とやや抽象的になるので避けた. typedef struct _line { int st; int ed; double prob; } Line; bool cmp(const _line& left, const _line& right) { return left.ed < right.ed; } typedef long long LL; class ContestSchedule { public: double expectedWinnings(vector <string> contests) { int sz = contests.size(); vector<Line> line(sz); //Parse for(int i = 0; i< sz; i++) { sscanf(contests[i].c_str(), "%d %d %lf", &line[i].st, &line[i].ed, &line[i].prob); line[i].prob = line[i].prob*1.0/100; } sort(line.begin(), line.end(), cmp ); map<LL, double> table; double res = 0; //return map<LL, double>::iterator it; int prev = 0; //prev-end_point //Traverse、ある種のDP。 for(int i = 0; i < sz; i++) { int pos = (line[i].st-prev >= 0) ? line[i].st : prev; //始点が終点より後にある-->始点をtableに格納 double p = line[i].prob; //table[終点]にとりうる最大値を格納したい. for(int j = 0; j < i; j++) { if(line[i].st >= line[j].ed) { //いま着目している始点が別の線の終点よりも大きい時、連続してcontestに参加できる. it = table.equal_range(line[j].ed).first; it--; p = max(line[i].prob+table[ it->first ], p ); } } res = max(p, res); table[pos] = res; table[ line[i].ed ] =res; prev = line[i].ed; } return res; }
//こっちの方が簡潔だが、本質的にやっていることは同じ. typedef struct _line { int st; int ed; int prob; } Line; class cmp { public: bool operator()(const _line& left, const _line& right) { if(left.ed != right.ed) { return left.ed < right.ed; } else { return left.st < right.st; } } }; typedef long long LL; class ContestSchedule { public: double expectedWinnings(vector <string> contests) { int sz = contests.size(); vector<Line> line(sz); for(int i = 0; i< sz; i++) { sscanf(contests[i].c_str(), "%d %d %d", &line[i].st, &line[i].ed, &line[i].prob); } sort(line.begin(), line.end(), cmp() ); //終点のまわりに昇順ソート。 int dp[51]; //ここで、dp[時間] = probではなくて、dp[インデックス] = probというDPの取り方をしている. memset(dp, 0, sizeof dp); for(int i = 0; i < sz; i++) { dp[i] = line[i].prob; } for(int i = 1; i < sz; i++) { for(int j = 0; j < i; j++) { if(line[i].st >= line[j].ed) { dp[i] = max(dp[i], dp[j]+line[i].prob); //iの始点がjの終点より後になるときだけjのコンテストに引き続いてiのコンテストに参加することができる. } } } return (*max_element(dp, dp+51) )*1.0/100; } };