結果
問題 | No.362 門松ナンバー |
ユーザー |
![]() |
提出日時 | 2022-11-04 19:19:47 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 131 ms / 3,000 ms |
コード長 | 11,258 bytes |
コンパイル時間 | 3,137 ms |
コンパイル使用メモリ | 255,620 KB |
最終ジャッジ日時 | 2025-02-08 17:10:36 |
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 19 |
ソースコード
/*** @FileName a.cpp* @Author kanpurin* @Created 2022.11.04 19:19:40**/#include "bits/stdc++.h"using namespace std;typedef long long ll;struct Monoid {using T = ll;T val;bool undef = true;Monoid() { *this = zero(); }Monoid(T val, bool undef = true) : val(val),undef(undef) {}static Monoid zero() { return Monoid(0); }static Monoid e() { return Monoid(1,false); }Monoid& operator+=(const Monoid &a) {if (this->undef) *this = a;else if (!a.undef) this->val += a.val;return *this;}Monoid& operator*=(int c) {return *this;}friend Monoid operator+(const Monoid& a, const Monoid& b) {return Monoid(a) += b;}friend Monoid operator*(const Monoid& a, int c) {return Monoid(a) *= c;}friend std::ostream& operator<<(std::ostream &os, const Monoid &x) {return os << x.val;}};struct Automaton {vector<vector<int>> delta;vector<bool> is_accept, is_reject;int qsize;int init;int alphabet_size = 10;inline int next(int state, int c) const { return delta[state][c]; }inline bool accept(int state) const { return is_accept[state]; }inline bool reject(int state) const { return is_reject[state]; }inline int size() const {return qsize; }};template<typename Automaton>Monoid digitDP(const string &s, const Automaton &dfa, bool eq = 1) {array<unordered_map<int,Monoid>,2> dp;dp[1][dfa.init] = Monoid::e();for (int i = 0; i < s.size(); i++) {array<unordered_map<int,Monoid>,2> dp2;for (int tight = 0; tight <= 1; tight++) {for (auto [state,value] : dp[tight]) {if (dfa.reject(state)) continue;int lim = (tight ? s[i] - '0' : dfa.alphabet_size - 1);for (int c = 0; c <= lim; c++) {int tight_ = tight && c == lim;int state_ = dfa.next(state,c);if (dfa.reject(state_)) continue;dp2[tight_][state_] += value*c;}}}dp = move(dp2);}Monoid ans = Monoid::zero();for (int tight = 0; tight <= eq; tight++)for (auto [state,value] : dp[tight])if (dfa.accept(state)) ans += value;return ans;}struct PartitionRefinement {unordered_map<int,unordered_set<int>> block;vector<int> block_id;int t;PartitionRefinement(int k) : block_id(k) {for (int i = 0; i < k; i++) {block[0].insert(i);block_id[i] = 0;}t = 1;}vector<pair<int,int>> partition(vector<int> &v) {unordered_map<int,int> split;for (int i = 0; i < v.size(); i++) {if (block[block_id[v[i]]].size() == 1) {if (split.find(block_id[v[i]]) == split.end()) continue;for (int p : block[split[block_id[v[i]]]]) {block_id[p] = block_id[v[i]];block[block_id[v[i]]].insert(p);}block.erase(split[block_id[v[i]]]);continue;}block[block_id[v[i]]].erase(v[i]);if (split.find(block_id[v[i]]) != split.end()) {block_id[v[i]] = split[block_id[v[i]]];block[block_id[v[i]]].insert(v[i]);}else {split[block_id[v[i]]] = t;block_id[v[i]] = t++;block[block_id[v[i]]].insert(v[i]);}}vector<pair<int,int>> res;for (auto p : split) {res.push_back(p);}return res;}void print() {for (auto [i,st] : block) {cerr << i << " [ ";for (int v : st) {cerr << v << " ";}cerr << "]" << endl;}}};Automaton Minimize(const Automaton& dfa) {vector<vector<vector<int>>> inv_delta(dfa.size(),vector<vector<int>>(dfa.alphabet_size));for (int state = 0; state < dfa.size(); state++) {for (int c = 0; c < dfa.alphabet_size; c++) {int t = dfa.delta[state][c];inv_delta[t][c].push_back(state);}}PartitionRefinement pr(dfa.size());vector<int> f;for (int state = 0; state < dfa.size(); state++) {if (dfa.accept(state)) f.push_back(state);}pr.partition(f);queue<pair<int,int>> que;for (int c = 0; c < dfa.alphabet_size; c++) {que.push({c,0});que.push({c,1});}while(!que.empty()) {auto [c,b_id] = que.front(); que.pop();vector<int> v;for (int state : pr.block[b_id]) {for (int p : inv_delta[state][c]) {v.push_back(p);}}if (v.size() == 0) continue;auto par = pr.partition(v);for (auto p : par) {if (pr.block[p.first].size() > pr.block[p.second].size()) {swap(p.first,p.second);}if (pr.block[p.first].size() == 0) continue;for (int c2 = 0; c2 < dfa.alphabet_size; c2++) {que.push({c2,p.first});}}}map<int,int> mp;for (int state = 0; state < dfa.size(); state++) {int b_id = pr.block_id[state];if (mp.find(b_id) != mp.end()) continue;mp[b_id] = mp.size();}vector<int> to_state(dfa.size());for (int state = 0; state < dfa.size(); state++) {to_state[state] = mp[pr.block_id[state]];}Automaton M;M.init = to_state[dfa.init];M.alphabet_size = dfa.alphabet_size;M.qsize = mp.size();M.delta.resize(M.qsize,vector<int>(M.alphabet_size));M.is_accept.resize(M.qsize);M.is_reject.resize(M.qsize);for (int state = 0; state < dfa.size(); state++) {for (int c = 0; c < dfa.alphabet_size; c++) {M.delta[to_state[state]][c] = to_state[dfa.next(state,c)];}if (dfa.accept(state)) M.is_accept[to_state[state]] = true;if (dfa.reject(state)) M.is_reject[to_state[state]] = true;}return M;}struct KadomatsuAutomaton : public Automaton {private:void initializer() {qsize = 11*11+1;init = 0;set_delta();set_is_accept();set_is_reject();}void set_delta() {delta.resize(qsize,vector<int>(alphabet_size,0));for (int i = -1; i < 10; i++) {for (int j = -1; j < 10; j++) {for (int k = 0; k < 10; k++) {if (i == -1 && j == -1 && k == 0) {delta[(i+1)*11+(j+1)][k] = 0;}else if (i != -1 && j == -1) {delta[(i+1)*11+(j+1)][k] = qsize-1;}else if (i == -1 && j != -1 && j != k) {delta[(i+1)*11+(j+1)][k] = (j+1)*11+(k+1);}else if (i == -1 && j != -1) {delta[(i+1)*11+(j+1)][k] = qsize-1;}else if (i == -1) {delta[(i+1)*11+(j+1)][k] = (j+1)*11+(k+1);}else if (i != j && j != k && i != k && (j==min({i,j,k})||j==max({i,j,k}))) {delta[(i+1)*11+(j+1)][k] = (j+1)*11+(k+1);}else {delta[(i+1)*11+(j+1)][k] = qsize-1;}}}}}void set_is_accept() {is_accept.resize(qsize,false);for (int i = 0; i < 10; i++) {for (int j = 0; j < 10; j++) {is_accept[(i+1)*11+(j+1)] = true;}}}void set_is_reject() {is_reject.resize(qsize,false);is_reject[qsize-1] = true;}public:KadomatsuAutomaton(int alpha_size = 10) {alphabet_size = alpha_size;initializer();}};struct CountNumberAutomaton : public Automaton {private:std::vector<bool> flg;int num;bool eq;void initializer() {assert(flg.size() == alphabet_size);qsize = num+3;init = num+2;set_delta();set_is_accept();set_is_reject();}void set_delta() {delta.resize(qsize,std::vector<int>(alphabet_size));for (int state = 0; state < qsize; state++) {for (int c = 0; c < alphabet_size; c++) {if (state == init && c == 0) delta[state][c] = init;else if (state == init) delta[state][c] = flg[c]?1:0;else if (state == num+1) delta[state][c] = state;else delta[state][c] = flg[c]?state+1:state;}}}void set_is_accept() {is_accept.resize(qsize,false);if (eq) is_accept[num] = true;else {for (int state = 0; state <= num; state++) {is_accept[state] = true;}is_accept[num+2] = true;}}void set_is_reject() {is_reject.resize(qsize,false);is_reject[num+1] = true;}public:CountNumberAutomaton(std::vector<bool> flg, int num, bool eq = false, int alpha_size = 10) : flg(flg),num(num),eq(eq) {alphabet_size = alpha_size;initializer();}};template<class Automaton1, class Automaton2>Automaton IntersectionAutomaton(const Automaton1 &A, const Automaton2 &B) {assert(A.alphabet_size == B.alphabet_size);Automaton M;M.alphabet_size = A.alphabet_size;vector<vector<int>> table(A.size(), vector<int>(B.size(),-1));vector<int> x = {A.init}, y = {B.init};table[x[0]][y[0]] = 0;M.init = 0;for (int i = 0; i < x.size(); ++i) {M.delta.push_back(vector<int>(M.alphabet_size, -1));M.is_accept.push_back(A.accept(x[i]) && B.accept(y[i]));M.is_reject.push_back(A.reject(x[i]) || B.reject(y[i]));for (int c = 0; c < A.alphabet_size; c++) {int u = A.next(x[i],c), v = B.next(y[i],c);if (table[u][v] == -1) {table[u][v] = x.size();x.push_back(u);y.push_back(v);}M.delta[i][c] = table[u][v];}}M.qsize = M.delta.size();return M;}int main() {int t;cin >> t;auto M = KadomatsuAutomaton();auto M2 = IntersectionAutomaton(M,CountNumberAutomaton({1,1,1,1,1,1,1,1,1,1},2));while(t--) {ll k;cin >> k;ll l = 0, r = 37294859064823;while(r-l>1) {ll mid = (l+r)/2;string sm = to_string(mid);if (k <= digitDP(sm,M).val-digitDP(sm,M2).val) {r = mid;}else {l = mid;}}cout << r << endl;}return 0;}