プログラマーに(?)おすすめしたい素数大富豪
この記事は、プログラマーにオススメしたいゲーム紹介 Advent Calendar 2018 6日目の記事です。
素数大富豪には、いろいろな楽しみ方があります!
など…
素数好きだけでなく、数学が嫌いだった人も*1、 幼稚園児も*2楽しんでます!!
さて、競プロにおなじみの素数といえば…そう!
を使ってみましょう!
用意するもの
- 998244353
- 91・1001・17・19・2001チェック
- 4枚7~8桁
- KTTQJ, KKTQJ, QJQTK, KTQ9J, 3TQKJ
- 偶数消費型素数
素数大富豪ver4☆pro☆でcpuと対戦です!
方針
- まずは全部出しで手札を2倍化(後攻の場合は合成数出しで2倍化)
- 2桁カードを使って返す
- 998244353が揃うまでドロー
- いい感じに手札が偏る(?)ので残りで手札を組んで勝つ
1戦目
以下標準的数譜案を使用します。
tatyam: [23456679JQX]
cpu: [1123389TJX]
まずは3の倍数でない最小の数を出します。(ドローしてからの方がよかったですね)
T: JQ2X3456679|X=2,P(124779TQKKK)
C: XJ=3*19*23|X=K
T: D(5)KK=K*T1
C: D(8)%
まだ揃ってないのでグロタンチェンジです!*5
T: D(5)57[GC]
ドローして揃いました!
T: D(3)99X244353|X=8
C: D(2)%
TTQQが使いにくいのでもう1度です!
T: D(6)TTJQQ6667#
おっと、出会い素数で勝利です!
2戦目
T: [344578TTJKX]
C: [1357889TJQQ]
T: D(Q)TTJXQK344587,P(122345678TKX)
C: 7QTQJ
24枚の手札を利用して、5枚10桁で応戦です!
T: D(2)KTTQJ
C: D(6)%
いまです!
T: D(9)9X8244353|X=9
C: D(9)%
一番大きい4枚出し: 8QTK から考えて…
グロタンカット: 57
偶数消費4枚: 6421, 6427, 2221
偶数消費3枚: 64X, 22X (X=1,3,7)
T: D(2)6421
C: D(1)9866,P(69JK)
T: 8XTK|X=Q
C: D(9)%
T: 57[GC]
T: 227#
やりました!!勝利です!
まとめ
JOI予選 2018-2019 参加記録
注意事項
- マクロを省略しています。マクロの内容はこちら
A - ソーシャルゲーム (Social Game)
急いで読むと問題が複雑に思えてくるのでシミュレーションを構築
提出1 WA
signed main(){ LL(a,b,c); rep(i,1,c+1000){ c-=a; if(i%7==0)c-=b; if(c<=0)return out(i); } }
途中でcの値が変わってしまうのでWA
提出3 AC
1度落ち着いて割り算を構築
signed main(){ LL(a,b,c); ll seven=a*7+b; ll ans=c/seven*7; c%=seven; if(c>a*6)return out(ans+7); out(ans+(c+a-1)/a); }
B - すごろくと駒 (Sugoroku and Pieces)
読んですぐにシミュレーションだなと思う
提出2 AC
signed main(){ LL(n); VEC(ll,x,n); x.push_back(2020); // 番兵を置く LL(m); rep(m){ LL(a); if(x[a]-1>x[a-1])x[a-1]++; } rep(n)out(x[i]); }
C - マルバツスタンプ (Circle Cross Stamps)
OXが隣り合っているところを順番に数えれば良さそう(貪欲になることを自明として見ていますね)
提出4 AC
signed main(){ LL(n); STR(s); ll ans=0; rep(s.size()-1){ if(s[i]!=s[i+1]){ ans++; i++; // 隣り合っていたら1つ読み飛ばす continue; } } out(ans); }
D - 日本沈没 (Japan Sinks)
日本沈没!?
シミュレーションを工夫して数えるだけ、はー気合い入れたのにDPじゃないのかー。
最初日本が1つの島だと考えて、低い区間から順番に沈めていって、隣の区間が沈んでいるかどうかで島の数が増えるかを判断します。
- 両方陸の時
□□□□□ → □□■□□ 増える
- 片方陸の時
□□□■□ → □□■■□ 同じ
- 両方海の時
□■□■□ → □■■■□ 減る
計算量はです。
提出5 WA
signed main(){ LL(n); vec(bool,sink,n); vec(pll,a,n); rep(n){ LL(b); a[i]={b,i}; // pairに位置情報を入れてからソート } sort(range(a)); ll island=1,ans=1; rep(n){ sink[a[i].second]=1; island++; // 1度増やしてから、隣の海の分減らす if(!a[i].second||sink[a[i].second-1])island--; if(a[i].second==n-1||sink[a[i].second+1])island--; if(i+1!=n&&a[i].first==a[i+1].first)continue; // 高さが同じ分は同時に処理する update_max(ans,island); } out(ans); }
4ケースWA、制約をよく見るとすでに日本沈没している場合が存在して、その場合は0を出力しないといけないらしい。
提出6 AC
変更
signed main(){ LL(n); vec(bool,sink,n); vec(pll,a,n); ll sum=0; rep(n){ LL(b); sum+=b; a[i]={b,i}; } if(!sum)return out(0); : : :
E - イルミネーション (Illumination)
- それぞれの木について入っている区間を持つ?
- とりあえず紙に書いて考えよう
- ある木を飾り付けると、ある区間が飾れなくなる
- それは前計算できそう
- その木を飾った時にどこまで飾れなくなるかの配列を作ってナップサックDP
計算量はソート + です。
提出7 AC
ll n,m; vector<ll>a,jump,mem; ll dp(ll at){ if(at==n)return 0; if(mem[at]!=-LINF)return mem[at]; if(jump[at]==-1)return mem[at]=dp(at+1)+a[at]; return mem[at]=max(dp(at+1),dp(jump[at])+a[at]); } signed main(){ in(n,m); a.resize(n); jump.assign(n,-1); mem.assign(n,-LINF); in(a); VEC(pll,duzzle,m); sort(range(duzzle)); ll mx=duzzle[0].second,at=0; rep(i,duzzle[0].first-1,n){ while(at<m-1&&duzzle[at+1].first-1<=i){ update_max(mx,duzzle[at+1].second); at++; } if(mx>i)jump[i]=mx; } out(dp(0)); }
F - 座席 (Seats)
か?なにもわからない。 とりあえずnext_permutationを使って6点
まとめ
ABCDEf 506点でした。Dが簡単だったのでボーダーが400を超えるかなー?と思っています。
春合宿に行きたい!!!