ABC107B解けた

投稿者: | 2018年9月11日

最近何もしてなくて何してるんだろうというぐらいに何もしてません。気がついたら解いてない問題が溜まってたので、とりあえずA問題とB問題を解いてました。いつもはC問題解けたらメモ代わりに書いてますが、今回はABC107のB問題です。2次元配列を縦と横に探索していくので、後で使えるかなあと思ってます。いやこれぐらいはいつでも使えるようにはしたいですが・・・。

[blogcard url=”https://beta.atcoder.jp/contests/abc107/tasks/abc107_b”]

まずは問題を読む

感覚としては、選択した部分を削除して左詰め/上詰めするような、エクセルの行/列削除みたいな感じです。消す部分は、全て’.’で成っている行/列。エクセルだったら、何もデータの入ってない行や列を削除する感じかなあ?とか思ってました。

とりあえずやることとしては、「一列または一行が全て’.’の行や列を削除し、その部分を詰める」コードを書くことになります。

詰める?

消す部分を探してその空いた部分を詰めて表示するというコードを書かなくてはなりません。しかし、配列の空いた部分を詰めるって大分めんどくさそう・・・。なので、あとで消す部分がわかるように、違う文字で置き換えておきます。そして出力するときに、その文字を出力しないようにすれば、出力されたデータは詰められた状態になります。

消す部分を探す

探し方は愚直に、一列または一行全部見て、全部’.’だったら違う文字に置き換え、です。早くなってるのか謎ですが、なんとなく、「一行または一列全て’.’なら、最低限、最初と最後は’.’じゃないと全部探す気にならないよねえ」とか思って、「行または列の最初と最後が’.’だった場合のみ、その行または列を見る」という書き方にしてます。

このとき、全て’.’だったら違う文字で置き換えるわけですが、条件文を「全て’.’だったら」というふうにしているとミスりました。私は行を見てから縦を見たわけですが、次のような場合、列を見るときに失敗します。

##.#
….
##.#
.#.#

まず行を見ていくと、2行目が全て違う文字で置き換えられます。行を見おわったら次は列を見ていきますが、3列目は全て違う文字に置き換えられるはずですが、2行3列目の文字は行を見ているときに違う文字で置き換えられていて、’.’ではないので、条件に一致せず、プログラムは「この行は全て’.’じゃなかった」と言って文字を置き換えません。このせいで20分使いました。

なので、後に行う処理の条件文は「’.’もしくは置き換えられた文字」にします。

綺麗に出力したい

一番時間かかったのが出力でした。ただ単純に「置き換えた文字は出力しない」ってやればいいやと思ったら、これ改行しなくちゃいけないんですね。その改行にすごく苦労してました。

普通に2次元配列の中身を表示すればいいんですが、そのままだと次のような感じになります。

出力
###

###
.##

2行目でも改行されて変な空白が出ます。これを消したい。なので、もうめんどくさくなってたので、bool型のflagという変数を作って、毎行文字を出力したらflag=1にして改行、そうでない場合は改行しないという、なんだかなあという感じになりました。

以上のことをコードにしたら、次のようになりました。

魔法少女プリティ☆ベル2巻を探す

投稿者: | 2018年9月3日

夏の暑さも一段落つき、虫の音色が秋の訪れを知らせてくれる今日このごろですが、いかがお過ごしでしょうか。私は雷雨のせいでロードバイクで走れず、というか未だにしまなみ海道のときのやってしまった右足の痛みが残ってるという、20代とは思えない回復力の無さに「これが20代・・・?」と愕然としています。

慣れない時候の挨拶で始めたのは、バイト中「時候の挨拶ってなあ、えーと・・・なんか、あー・・・堅苦しいやつ」という意味のわからない説明をしてしまったのを思い出したからです。

夏の暑さはまあ一段落した気はしますが、秋の訪れよりかはゲリラ豪雨の連続であり、フレシェット弾かよこれってなる程度の雨に降られ、ひでえ毎日です。

さて、珍しくwlwと自転車以外のことを書いてますが、そもそもこのサイトは”日記”であり、そういう感じでサイト作ってるので、何らおかしいことはありません。むしろ”日記”にwlwのことばっかり書いてるほうがやべーやつです。夏休みの日記に「今日はどういう試合をして、どこが反省点で、ビルドはこうしたほうが良いのでないか」とか毎日書いてるやつがいたら、再提出を食らいます。そもそも日記を再提出させてる時点で日記ってなんだっけ?ってなるんですが・・・。

今回書きたいのは”コミック”のことです。もっと言えば、なぜかシリーズの中で何かの巻だけどこにも売ってない状態です。

続きを読む

ABC103 C問題解けた

投稿者: | 2018年8月15日

今回解いた問題は、余りの合計の最大値を求める問題です。

[blogcard url=”https://beta.atcoder.jp/contests/abc103/tasks/abc103_c”]

わかってしまうと「なんだこれ、B問題レベルじゃねえか!」ってなる問題でした。

解法

最初考えたこと

全く頭が動かない状態で問題を読んでたので、とりあえず”愚直なコードを書いてmを求める”ということをしてました。以下がそのコードです。

はじめは、与えられる数列の最大値の余りが最大となるときのmのときだろって考えてたので、mを探すループ部分は以下の部分です。

[cpp] for(int i=1;i<100000*max;i++){ int sum=0; for(int j=0;j<n;j++){ sum+=i%a[j]; } if(sum>ans){ ans=sum; m=i; } } [/cpp]

sample2ぐらいならすぐ見つかると思ってたんですが全く答えと一致しなかったので、やけくそでループ回数増やしてます。アホですね。

ただ、やけくそでmを求めたおかげで、欲しいmの値は何でも存在するということに気がつけました。

真面目な解法

アホなことをしたお蔭で、欲しいmは必ず存在するということがわかりました。なので、もっとシンプルに考えます。

余りの合計が最大のときはどのような時かといえば、すべての余りが最大のときの合計値です。

例えば2なら余りの最大値は1、3なら2、10なら9・・・のように、その数の余りの最大値はその数自身より1小さい数です。

よって、求める解は、与えられた数列から1引いた数値の合計値となります。ということで、私の書いたコードは次のようになりました。

コンテスト中ならこういうのはさっさと解きたいものですが、そうじゃないのでまあ失敗するのもいいかなあって。

ただ、mを愚直に求めに言ったのは問題慣れしてないというか、なんというか・・・という・・・。精進します。

ABC094 C問題解けた

投稿者: | 2018年8月12日

いろいろとやってたら、気がつけばプログラムを書くという動作を1ヶ月ぐらいしてないことに気が付きました。

はっきり言ってマジでやべーです。配列が0スタートなのを忘れてバグ出しまくりました。

今回解いた問題は次の問題です。解法はバイト中に思いつきました。

[blogcard url=”https://beta.atcoder.jp/contests/abc094/tasks/arc095_a”]

中央値とは

私がまず躓いたのが「中央値って何だっけ?」ってことです。電流や電力と戯れてたら忘れました。

中央値とは

中央値(ちゅうおうち、英: median)とは、代表値の一つで、有限個のデータを小さい順に並べたとき中央に位置する値。たとえば5人の人がいるとき、その5人の年齢の中央値は3番目に年寄りな人の年齢である。ただし、データが偶数個の場合は、中央に近い2つの値の算術平均をとる。

wikipedia

sortした配列のど真ん中取ればいいということですね。

解法

まず元の配列をsortし、sortした配列の中央値を取ります。この時nは偶数ということが問題で保証されているので、中央値は2つ取ります。

次に元の配列を前から取り出し、先程の中央値と比較します。この時、比較する中央値は小さい方、大きい方どちらでもいいですが、それぞれ条件がちょっとだけ変わるので注意です。

最後に、中央値と元の配列の値を比較し、大きければ小さい方の中央値、小さければ大きい方の中央値を出力します。

以上のことをプログラムすると、次のようになります。

[cpp]

#include &lt;iostream&gt;
#include &lt;algorithm&gt;
using namespace std;
int main(int argc, char const *argv[]) {
int n;
cin&gt;&gt;n;
int a[n],b[n];
for(int i=0;i&lt;n;i++){
int tmp;
cin&gt;&gt;tmp;
a[i]=tmp;
b[i]=tmp;
}
sort(b,b+n);
// for(int i=0;i&lt;n;i++){
// cout&lt;&lt;b[i]&lt;&lt;",";
// }
// cout&lt;&lt;endl;
int med1=b[n/2-1],med2=b[n/2];
// cout&lt;&lt;med1&lt;&lt;","&lt;&lt;med2&lt;&lt;endl;
for(int i=0;i&lt;n;i++){
cout&lt;&lt;((a[i]&lt;med2)?med2:med1)&lt;&lt;endl;
}
return 0;
}

[/cpp]

バイト中にこれを思いついた時、自分のバカさ加減に呆れてました。「なんでこれをすぐに思いつけなかったのか・・・」と。

まず中央値ってなんだっけ?ってあたりからやばいです。ちゃんと勉強しよう・・・。

VANQUISHクリア

投稿者: | 2018年7月7日

tiwtter眺めてたら「VANQUISHってゲームが凄く面白いし、今steamセール中だから!!」っていうのがあったので、買って今一通りクリアしたので、その感想。

このゲームのウリのシステムはARモードらしい。スローモーションになっていろいろな行動ができるというやつです。よくわからずに「とりあえずスローモーションになったら弾避けたり敵撃ったりすればええんやろ?」と思ってたんですが、自分が投げた手榴弾を起爆できるらしい。そういった行動を繋げていける・・・らしいです。今人のレビュー読んで知りました。

続きを読む

Visual Studio Codeのメモ書きとか色々

投稿者: | 2018年6月28日

珍しくABC C問題が解けたから、調子に乗ってメモ書いた時、「Visual Studio CodeってWeb系書きやすいとか言ってたなあ」というのを思い出して、Visual Studio Codeをインストール。とりあえず使ってみました。

感想としては、「普通に使いやすくね・・・?」

私が最後にVisual Stuido Codeを触ったのが、出たばっかの時で、そのときは「Atomでええやん」となっていましたが、色々と便利になってから使ってみるととても使いやすいです。

  • ・軽いのでサクッと書くことができる
  • Emmetが標準で入ってる
  • 見やすい

AtomならEmmetはパッケージで入れればいいし、見やすさもカスタマイズすればいいんですけど、軽さだけはどうにもできない。早いのは正義ですね。

それはそうと、これは自分がよく使いそうな機能とかそういうのをメモしときます。

Visual Stuio Codeでの折返し

ショートカットキーはAlt+Zです。
[card url=”https://qiita.com/Ouvill/items/6fd08347602752acafe5″ title=”[Visual Studio Code]ウィンドウ幅の右端で行を折り返す。”]

ターミナルからVisual Stuido Codeを起動

shellをインストールすればいいです。

  1. Visual Stuido Code起動した状態でComand + SHift + Pでコマンドパレットを開く
  2. “Shell”と検索
  3. シェルコマンド:path内に”code”コマンドをインストールします、と選択

これで、ターミナルからVScodeが起動できるようになりました。
[card url=”https://qiita.com/naru0504/items/c2ed8869ffbf7682cf5c” title=”ターミナルからVisual Studio Codeを起動する方法【公式の方法】”]

HTMLファイルをプレビュー

プラグイン”Live HTML Previewer”をインストール。

インストール後再起動すれば終わり。

横にプレビューを表示するときは、コマンドパレット(Command+Shft+P)を開いて“show side preview”と入力して選択。いちいちCtrl+Sしなくていいから楽です。

以下はVS codeのことではなく、EmmetやMathjaxについてです。

Emmetでマークアップ

知ってたけど使ってなかった・・・めっちゃ便利やんけ!!

リスト作りたいときは”ul>li*3″と打てば要素数3のリストできるし、”h1+p”と打てば、見出しと段落でてくる。

詳しくは下のサイトがいいと思いいました。
[card url=”https://www.granfairs.com/blog/staff/efficiency-by-emmet-01″ title=”Emmetでマークアップを効率化しよう(HTML&カスタマイズ編)”]

Mathjaxで数式を書く

大学生なのにLaTeXが書けません。というか、レポートが手書きばっかで死にたくなります。

Mathjaxを使う

1,以下のコードをヘッダーに追加する

<script type=”text/javascript”
src=”https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-AMS-MML_HTMLorMML”>
</script>

2,プラグインをインストール(wordpress)
“Mathjax Latex”をインストールすればすぐに使えます。
どちらにせよ、Mathjaxを使うときは、式の両端に$$を付ける必要があります。
[card url=”https://bloglife.info/html-suusiki/” title=”HTMLで数式はどれだけ表せる?複雑な式を表示するには”]

インライン数式

文章中に数式を入れたい場合、インライン数式で本文の埋め込みます。
その時、 (…) で囲んで記述すれば、インライン数式として本文に埋め込めます。
[card url=”http://text.baldanders.info/remark/2017/10/getting-started-mathjax-3/” title=”ちょこっと MathJax: インライン数式と別行立て数式”]

ABC100 C解けた

投稿者: | 2018年6月28日

久しぶりにABCのC問題を真面目に解けたのでメモ。私のようなプログラム書けない馬鹿でもたま〜にちょっと整理すれば数学的に解ける問題あるから楽しい。私がまともに解けた問題は以下の問題。
[blogcard url=”https://beta.atcoder.jp/contests/abc100/tasks/abc100_c” title=”C – *3 or /2″]
問題を整理すれば、

    • “すべて”の数列の要素に対して
    • 2で割る
    • 3掛ける(ただし全て3を掛けてはいけない)

最初問題読んだ時、”すべて”というのを見落として、「これ無限に終わらなくね?」ってなりました。問題文はちゃんと読もう。
さて、ちゃんと問題を理解したところで、問題を解いていきましょう。

1,とりあえず偶数だけ考えれば良い

2と3は互いに素なので、3はいくらかけても2で割るという行為には影響しません。また、2で割れない奇数は3掛ける操作しかできない為、偶数のみ考えればいいということがわかります。
そこで最初に考えたことが、「2で割れる回数の最大回数じゃね?」ということですが、サンプル1でそれはおかしいことがわかります。しかし、2で割る回数という方針は正しかったです。
最初に考えた解法がコードを書いてサンプル1を通した瞬間に間違えてることがわかって落胆したので、次の解法を考えます。

2,とりあえず2で割ってしまう

「2で割れる回数」という方針は正しいはずです。でなければ、問題にがわざわざ「2で割る」という操作をさせるはずがありません。なので、この方針はそのままに真面目に考えました。
さて、「2で割る」ですが、どこまで「2で割る」のでしょうか。これは、「すべての要素に対して3倍できない」というところから考えられます。つまり、「すべての要素が2で割れなくなった」ところまで要素を割り続けます。
では、どのようにして「2で割り」ましょうか。求める解は「最大回数」ですので、2で割れる要素を同時に2で割ると、2で割るという操作が1回分回数が節約されます。これだと最大回数にならないので、考えるべきは「各要素を一個ずつ2で割っていく」という操作だとわかります。
また、複数の偶数に対して2で割れる最大回数を求める時、ある偶数を2で割り切れなくなるまで2で割り続け、2で割り切れなくなったら次の偶数を2で割り続けると考えればうまくいきます。また、2で割れきれなくなった偶数はその後考えませんが、思考の外では、これらは3を掛け続けている状態となっています。
まとめると、「各要素1個ずつ、その要素が2で割れなくなるまで2で割り続け、最終的にそのそれぞれの2で割った回数を足し合わせればいい」となります。
このあたりは、簡単な図をかいてみるとわかりやすかったです。
以上のことをプログラムで書くと次のようになりました。

[cpp]
        #include &amp;amp;amp;lt;iostream&amp;amp;amp;gt;
                using namespace std;
                int counter(int);
                int main(int argc, char const *argv[]) {
                  int n;
                  cin&gt;&gt;n;
                  int ans=0;
                  for(int i=0;i&amp;amp;amp;lt;n;i++){
                    int tmp;
                    cin&gt;&gt;tmp;
                    if(tmp%2==0)  ans+=counter(tmp);
                  }
                  cout&lt;&lt;ans&lt;&lt;endl;
                  return 0;
                }
                int counter(int a){
                  int count=0;
                  while(1){
                    if(a%2==0){
                      count++;
                      a=a/2;
                    }else{
                      break;
                    }
                  }
                  return  count;
                }
        [/cpp]

これを実行した結果、実行時間は7msでした。結果一覧を見てみると、こういう書き方をした場合7msのようです。しかし、実行時間2msの人もいるので、もっと高速化できるんだと思いました。
とは言っても、「2で割りまくる」というのは同じです。しかし、私がどうやって書いても2msにならなかったので諦めます。また、上のコードは無駄ばっかだったので、もっと短く書き直しました。

[cpp]

#include &lt;iostream&gt;
using namespace std;
int main(int argc, char const *argv[]) {
int n;
cin&gt;&gt;n;
int ans=0;
for(int i=0;i&lt;n;i++){
int a;
cin&gt;&gt;a;
while(a%2==0) a/=2,ans++;
}
cout&lt;&lt;ans&lt;&lt;endl;
return 0;
}

[/cpp]

最初からこれで書けばよかった・・・。