AtCoder Beginner Contest 110
AtCoder Beginner Contest 110 - AtCoder
A - Maximize the Formula
考察
与えられた3つの1桁の数字を順不同にとするとき、の最大値を求める。結局に何が入るかを場合分けすれば、取りうる値はたかだか3通りなのですべて調べればよい。
コード
int main(){ int a,b,c; cin >> a >> b >> c; int ans = max(max(a*10+b+c,a+b*10+c),a+b+c*10); cout << ans << endl; return 0; }
B - 1 Dimensional World's Tale
考察
A帝国の首都とその支配に置きたい都市、およびB帝国の首都とその支配に置きたい都市が数直線上でオーバーラップしていないかどうかを判定すればよい。前者の座標の最大値と後者の座標の最小値を比較することで判定ができる。
コード
int main(){ int n,m,x,y; cin >> n >> m >> x >> y; int x_max = x; REP(i,n){ int xi; cin >> xi; x_max = max(x_max,xi); } int y_min = y; REP(i,m){ int yi; cin >> yi; y_min = min(y_min,yi); } if(x_max<y_min){ cout << "No War" << endl; }else{ cout << "War" << endl; } return 0; }
C - String Transformation
考察
長さが等しい2つの文字列とが、文字の入れ替え(「いっぱい」を「おっぱお」にするような入れ替え)によって変換できるかどうかを答える。これは、の中で同じ文字はで同じ文字に対応し、の中で違う文字はで違う文字になっているかどうかと同値である。よって、2つの文字列の各文字について「その文字が最初に出てくるその文字列内の場所」を計算しておき、比較すれば、判定ができる。
コード
int main(){ str s,t; cin >> s >> t; int n = s.length(); map<char,int> mp_s; int group_s[n]; REP(i,n){ if(mp_s[s[i]]==0){ mp_s[s[i]]=i+1; } group_s[i]=mp_s[s[i]]; } map<char,int> mp_t; int group_t[n]; REP(i,n){ if(mp_t[t[i]]==0){ mp_t[t[i]]=i+1; } group_t[i] = mp_t[t[i]]; } REP(i,n){ if(group_s[i]!=group_t[i]){ cout << "No" << endl; return 0; } } cout << "Yes" << endl; return 0; }
D - Factorization
考察
かけてになるような個の数のパターンの数を求める(ただしで割った余り)。とりあえずを素因数分解し、ある素数について乗となっているとき、この個のを個のグループに分割する方法は通りある。これをすべての素数に関して計算して積を取ればよい。
ただし、組み合わせを計算するときはオーバーフローに注意する必要がある。より、はlong long型でも容易にオーバーフローすることがわかるので、組み合わせをで割ったあまりを工夫して求める必要がある。まず、
と変形し、分子と分母をで割った余りを計算しておく。そして、「分母で割る」ことと「ある整数をかける」ことが等価となる整数(における逆元)を求め、分子にその整数をかけることによって組み合わせをで割った余りを求める。
逆元の求め方は蟻本の4-1章に記載があるほか、Web上にも資料がある。
http://hos.ac/slides/20130319_enumeration.pdf
コード
map<ll,ll> prime_factor(ll n){ map<ll,ll> res; for(ll i = 2; i * i <= n; i++){ while(n%i==0){ ++res[i]; n/=i; } } if(n!=1) res[n] = 1; return res; } const ll p = 1000000007; ll extgcd(ll a, ll b, ll& x, ll& y){ int d = a; if(b!=0){ d = extgcd(b,a%b, y, x); y -= (a/b)*x; }else{ x = 1; y = 0; } return d; } ll mod_inv(ll n){ ll x,y; extgcd(n,p,x,y); return (p+x%p)%p; } int main(){ ll n,m; cin >> n >> m; map<ll,ll> factor = prime_factor(m); ll ans = 1; for(auto b : factor){ int x = b.second; ll num = 1, den = 1; REP(i,x){ num = num * (x+n-1-i) % p; den = den * (x-i) % p; } ans *= num*mod_inv(den)%p; ans = ans % p; } cout << ans << endl; return 0; }
雑感
今週も用事で参加できず。休日の夜は参加しづらいです。
Dは逆元やらなにやら調べていたらかなり時間がかかりました。
Touch Barでメールの未読を通知する
Dockを消したい
MacOSには下部にはDockという、起動中のアプリケーションを表示しておく場所があります。各アプリケーションのアイコンの右上には、通知がある場合にその数が赤い丸で表示されます。一目で通知があるかを確認できるので、結構便利です。
ただ、Dockは下部のスペースを占領してしまって邪魔なので、隠したいというのは本当のところ。しかしそうすると、この通知のバッジも見られなくなってしまうのでメールが来ているかどうかを一目で確認することができません。そこで今回は、Touch Bar上に未読メールがあるかどうかを表示させるようにしてみたいと思います。
未読メールがあるかどうかをチェックする
MacOSで未読メールがあるかどうかを判断する方法として、以下の2つがあります。
- デフォルトのメールアプリMail.appから未読メール数を取得する
- メールサーバから未読メール数を取得する
前者はオフラインでも実行できるところが優れています。ただ、Mail.appから直接未読数を取得することができないため、メールを一通ずつ取得して未読かどうかを判断し、それをカウントすることになります。コードは以下のとおりです。
tell application "Mail" set unread to 0 repeat with msg in messages in inbox if msg's read status is not true then set unread to unread + 1 end if end repeat end tell return unread
やっていることは単純で、メールボックスのメールをすべて取り出して、ループで回しています。想像はつくと思いますが、これを実行するのにはかなり時間がかかり、システムの負担も大きいです。これでは常駐させるにはあまりにも向いていないため、メールサーバにアクセスする方法を取ることにしました。
僕はメインでGmailを使っているのですが、Gmailには未読メールを簡単に取得できるURLが存在します。URLにアクセスし、ユーザ名とパスワードを入力することで、未読メール数と各メールの概要をXML形式で取得することができます。fullcountというところを読めば、未読メールがいくつあるかを取得できます。
https://mail.google.com/gmail/feed/atom
<feed xmlns="http://purl.org/atom/ns#" version="0.3"> <title>Gmail - Inbox for <メールアドレス></title> <tagline>New messages in your Gmail Inbox</tagline> <fullcount>1</fullcount> <link rel="alternate" href="https://mail.google.com/mail" type="text/html"/> <modified>2018-09-12T05:54:12Z</modified> <entry> <title>テスト</title> <summary>本文です。</summary> ... </entry> </feed>
これを利用して、以下のスクリプトを書きました。
set xml_data to do shell script "curl -u \"<ユーザ名>\":\"<パスワード>\" --silent \"https://mail.google.com/mail/feed/atom\"" tell application "System Events" set xml_data to make new XML data with data xml_data set unread to xml_data's XML element "feed"'s XML element "fullcount"'s value end tell return unread
まずシェルスクリプトで先ほどのURLにアクセスしてXMLを受け取り、それをMacOSのSystem Eventsでパースし、
BetterTouchToolでウィジェットを作成
あとはこのスクリプトを組み込んだウィジェットをBetterTouchToolで作成します。
nexusuica.hatenablog.jp
定期的に上のスクリプトを実行し、実行結果が1以上であればアイコンと背景色を変更するようにしておきます(「Run Apple Script and Shown Return Value」)。また、アイコンをタッチするとMail.appが起動するようにしておきます(Action)。作成したものがこちら。これでDockを隠しておいたとしてもメールに気付かないということがなくなります。Touch Barも便利なものですね。
1,2,...,nからm個をランダムに取ってきたときの最小値の平均値
事の発端
事の発端は、塾で教えている生徒から来た、ある問題に関する質問でした。
いま、1から100のうち、最小の数となりうるのは1から98である。この範囲のある整数をとおき、最小の数がとなる確率を求めると、最小でない残り2枚を以上以下の数から選ぶ確率なのでである。よって求める期待値は
となる。
の中はの3次式なので手計算は一応可能で、実際に計算するととなります。ただ、この問題がもともと穴埋め式の問題だったことと、最後の答えが綺麗にになっていたので、何かもっと綺麗な解法があるのではないかとTwitterに助けを求めました。すると、非常に様々な解法が寄せられました。 togetter.com
最終的にこれだ、というものがあったので、その解法と地道に計算する方法、2通りの解法を紹介します。
せっかくなので一般化
先ほどの問題だと具体的すぎるので、ここから先は一般化して次の問題を考えます。
コンビネーションをガリガリ計算する方法
まずは先ほどと同様に定義どおり計算します。最小の数となりうる整数について、最小の数がとなる確率は、最小でない残り枚を以上以下の枚から選ぶ確率なのでとなります。これを用いて期待値は
と立式できます。ここで、
を用いることで、上の期待値は
と書き直すことができます。 さてここでいったん、を考えます。二項係数の性質
を繰り返し用いれば、
となることがわかります。これをのの第1項にはとして、第2項にはとして代入することで、
が導出できました(ふう……)。
もっとエレガントに解く方法
さすがに二項係数の計算は疲れます。もっと直感的な解法はないのでしょうか。もう一度問題を見てみましょう。
いま、これらの差に着目して個の数字を、
によって定めます。このとき、とは1対1に対応します。
が常に成立すること、および最小値に注意すると、以下のように問題が言い換えられることがわかります。
となることが容易にわかります。なんと……。
このように、適当な1対1対応を作ることで期待値が簡単に求まってしまう場合があるんですね。
Macを超カスタマイズできる「BetterTouchTool」
何ができるの?
以前の記事では、MacBookを無料のソフトウェアのみを用いてカスタマイズしてみました。
nexusuica.hatenablog.jp
今回は「BetterTouchTool」という有料アプリでカスタマイズを一歩進めてみたというお話です。
「BetterTouchTool」は トラックパッドやマウス、キーボード、トラックパッドの動作をカスタマイズできるソフトウェアで、「ある動作をしたら(トリガー)、この操作を実行する(アクション)」というような設定を非常に細かく行えます。例えば、「Commandキー+Optionキー+Cを押したら、Google Chromeを起動する」といったようなものです。BetterTouchToolは、トリガーの入力パターンが非常に多彩な上、アクションの種類も非常に豊富であるのが特長で、無料ソフトウェアにこれを追随するものはありません。特に、アクションとしてシェルスクリプトやApple Scriptの実行ができるのでかなり自由度が高いです(かなりコアなユーザー向けですが)。
僕はこのBetterTouchToolを用いて、Touch Barのヘビーカスタマイズをしてみました。このTouch Barのカスタマイズに関しては別の記事で紹介したいと思います。
購入方法
このBetterTouchToolですが、まずは購入する前に試用することが出来ます。公式サイトからダウンロードして起動すれば、45日間は無料ですべての機能を使用できます。その後、ライセンスを購入するかどうか判断できます。
https://folivora.ai
ライセンスを購入する場合、2年間のみアップデートが提供されるものと永久にアップデートを受けられるものがあります。記事執筆時点で前者が$6.50、後者が$20です。さすがに$20はちょっと高いので、2年間のアップデート付きライセンスですかね…。ただ実はこのライセンス、もっと安く買う方法が存在します。
App Storeで同じ開発者が販売しているアプリ「BetterSnapTool」(記事執筆時点で360円)を購入すると、なんと「BetterTouchTool」のライセンスをもらうことが出来ます。
Mac生活が確実に豊かになるBetterTouchTool、まずは試用してみて気に入ったら購入してみてはいかがでしょうか。