バイトの競プロメモ

主に競技プログラミング

No.832 麻雀修行中

https://yukicoder.me/problems/no/832

 

解法

まず与えられた14枚があがりの形であるか判定する方法を考えます

 

これが難しいのは、ABCやBBB等の二つの揃え方があるためです

ここで、AAAは一つしか作れない(Aは4枚しかない)事に気付くと、同じ3つ組を作る数字の集合ををビットマスクで持ち、全て試せばいいと分かります

その上で2枚組にする数字を9パターン試し、ABCの形だけで不足分を補えればあがりです

 

初期状態にi(1 ~ 9)を加えたものがあがりの場合、iはあがり牌です

 

また、AABBCCDDEEFFGGの形は別途に調べます 

 

↓は与えられたものをマイナスしていき、全て0に出来たらあがりという実装です

https://yukicoder.me/submissions/348869


template<class T> inline T min(vector<T> a) { return *min_element(all(a)); }
template<class T> inline T max(vector<T> a) { return *max_element(all(a)); }

constexpr bool bget(ll m, int keta) {
assert(keta < 64);
return (m >> keta) & 1;
}
bool toi(vi cou, int p) {
cou[p]++;
rep(i, 1, 10) {
if (cou[i] & 1 || cou[i] == 4)return 0;
}
return 1;
}
signed main() {
string s;
cin >> s;
n = s.size();
vi cou(13);
rep(i, n)cou[s[i] - '0']++;
rep(ad, 1, 10) {
if (cou[ad] == 4)con;
if (toi(cou, ad)) {
cout << ad << endl;
continue;
}
rep(he, 1, 10) {
rep(tm, 1 << 10) {
vi tem = cou;
tem[ad]++;
tem[he] -= 2;
rep(i, 1, 10) {
if (bget(tm, i)) tem[i] -= 3;
if (tem[i] < 0)goto end;
tem[i + 2] -= tem[i];
tem[i + 1] -= tem[i];
tem[i] -= tem[i];
}
if (min(tem) == 0 && max(tem) == 0) {
cout << ad << endl;
he = 11;
break;
}
end:;
}
}
}


return 0;
}