第二回ニコ生オープン!!
第二回も参加したよ。
(詳細:http://com.nicovideo.jp/community/co329335 )
今回も主催の診断人さん、参加者のみなさんお疲れ様でした。
Result
8位 rankalee 236.82 / 444.20 / 0.0(challenge succeeded) / 0 challenge 681.02
みんな1000通ってる……くやしいなー。
自前でテストケースを考えて作るようにしないとこういうことがまた起こりそう。
と、というかW=H=1000のケースも一応テストしたつもりだったんだけどorz
プラグインを改造しないといけないな……情報収集しよう。
Easy SumRectangle
問題
何かの数字の書いてある同じ大きさの正方形を、長方形の形に並べたSum Rectangleがある。このSum Rectangleは次の条件を満たす。
一番右の列、下の列を除き、ある正方形に書かれた数字は、その正方形の右、下、右下の正方形に書かれた数字の和に等しい。
一番左の列および一番上の行の数字が全て与えられたとき、右下の正方形の数字を求めよ。
試行錯誤
読んだ。ちょっと良くわからないのでサンプルを見る。
ある正方形の数字はその下、右、右下の3つの数字の和になってるってことか。
左上から一マスずつ順に求めていけばおk.
問題文に不気味な一文が。右下がユニークに決まらないときは0を返せ。
あれ?ユニークに決まらないことないよな?考え方間違ってる?
まあいいやサンプル合った。変なケースもないっぽいし送信。
ソースコード
class SumRectangle { public: int getCorner(vector <int> leftColumn, vector <int> topRow) { int h=leftColumn.size(),w=topRow.size(); vector<vi> sq(h,vi(w)); rep(i,h)sq[i][0]=leftColumn[i]; rep(i,w)sq[0][i]=topRow[i]; for(int i=1;i<h;i++)for(int j=1;j<w;j++) { sq[i][j]=sq[i-1][j-1]-sq[i][j-1]-sq[i-1][j]; } return sq[h-1][w-1]; } };
Medium WhatsThisChord
問題
ギターのそれぞれの弦はフレットを抑えないとE,A,D,G,B,Eの音が出る。
1番目のフレットを抑えると、出る音は半音あがり、i番目のフレットを抑えると半音i個分出る音が上がる。
各弦の押さえるフレットの番号が与えられたとき、ギターの出す和音のコードを求めよ。
ただし-1はその弦を弾かないことを表す。
- 音階はC,C#,D,D#,E,F,F#,G,G#,A,A#,Bの12個で、Bの次はCに戻る。
- 考える和音はMajorとMinorのみで、それぞれ音の間隔がX,X+4,X+7およびX,X+3,X+7である。
- ギターの出す和音が上の和音以外のときは空の文字列を返せ。
試行錯誤
問題文長いwああでも音階とギターの説明してるだけか。
和音全部作ってmapに入れて参照すればいいんじゃないか。
書く。サンプル通った。送信。
ソースコード
string name[]={"A","A#","B","C","C#","D","D#","E","F","F#","G","G#"}; int open[]={7,0,5,10,2,7}; map<vi,string> cd; class WhatsThisChord { public: string classify(vector <int> chord) { rep(i,12) { vi v; v.pb(i),v.pb((i+4)%12),v.pb((i+7)%12); sort(all(v)); cd[v]=name[i]+" Major"; v.clear(); v.pb(i),v.pb((i+3)%12),v.pb((i+7)%12); sort(all(v)); cd[v]=name[i]+" Minor"; } set<int> key; rp(i,chord)if(chord[i]>=0)key.insert((open[i]+chord[i])%12); vi v; fr(i,key)v.pb(*i); if(cd.count(v))return cd[v]; return ""; } };
Hard CuttingGlass
問題
芝刈り……ではなくガラスを切る問題。
ガラスは幅W高さHの長方形で、カッターは最初(startX,startY)の座標にいる。
カッターの動かし方が次のような文字列で与えられるとき、カッターを動かした後でガラスが何枚のパーツに分かれたかを求めよ。
- 'U':カッターを上へ動かす(y座標-1)
- 'D':下へ(y座標+1)
- 'L':左へ(x座標-1)
- 'R':右へ(x座標+1)
W,H≦1000である。
試行錯誤
何のアルゴリズムの問題だろう。包除原理か何かか?
うん?1000x1000だと?これ単純に実装すればいいんじゃないだろうか。
カッターの切った線を覚えておいて、くっついてるガラスをdfsで求めて数えてやればパーツの数がわかる。最大ケースでたった100万だしおkな気がする。
かりかり。書いた。サンプルも合った。自分にしてはめずらしく順調。
最大ケースをテスト。エラー出てないよな。送信。あれこれ2位じゃね?w
ソースコード
int dy[]={-1,0,1,0},dx[]={0,-1,0,1}; int w,h; string pg; vector<vector<bool> > tate,yoko,V; class CuttingGlass { public: int pieces(int W, int H, int x, int y, vector <string> program) { w=W,h=H; pg=accumulate(all(program),string()); tate=vector<vector<bool> >(h,vector<bool>(w+1)); yoko=vector<vector<bool> >(h+1,vector<bool>(w)); V=vector<vector<bool> >(h,vector<bool>(w)); //cut rp(i,pg) { if(pg[i]=='U'||pg[i]=='D') { if(pg[i]=='U') { tate[y-1][x]=1; y--; } else { tate[y][x]=1; y++; } }else { if(pg[i]=='L') { yoko[y][x-1]=1; x--; } else { yoko[y][x]=1; x++; } } } //fill int ans=0; rep(i,h)rep(j,w)if(!V[i][j])ans++,dfs(i,j); return ans; } void dfs(int y,int x) { V[y][x]=1; rep(d,4) { int ny=y+dy[d],nx=x+dx[d]; if(ny<0||nx<0||ny>=h||nx>=w)continue; if(d==0&&yoko[y][x]||d==1&&tate[y][x]|| d==2&&yoko[y+1][x]||d==3&&tate[y][x+1])continue; if(!V[ny][nx])dfs(ny,nx); } } };
(Challenge Succeeded)
Challenge Phase
1000落とされた;;
スタックオーバーフローだったらしい。あれ、最大ケース試したはずが……
入力ミスでちゃんと試せてなかったぽい?
しょっく。
再帰dfsではなくstackまたはqueueを使えという問題だったようだ。
テストはしっかりしろ!
System Test
250,500は何とか通った……よかった。