## AtCoder Regular Contest 173A - Neq Number [<<回主頁](https://hackmd.io/@r1cky/Sk2hKzga6) ### 前言 打的時候過範測但一直 WA ,痛苦面具 ### 解法 先想另外一題 : > 給你一個正整數 $x$,我們想知道 $x$ 以下的 Neq Number 有幾個。 這個可以利用 digit dp 來解決。 定義 $dp_{d,i}$ 代表上一個填 $i$,然後後面 $d$ 位的選填方法,這裡的 $dp$ 是沒有限制的狀態(也就是沒有上界限制),接著特別處理貼著上界的 case 可以 $O(logx)$ 求出來。 那回到原題,我們可以二分搜答案,那每次就是檢查 $mid$ 以下的 Neq Number 和題目給的 $K$ 的數量關係決定左右界的調整,時間複雜度為 $O(Nlog^2K)$。 ### code ```cpp= #pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include <bits/stdc++.h> #define i64 long long #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); using namespace std; const i64 maxn = (i64)1e18; const int ma = 18; i64 dp[ma+5][11]; i64 qpow(i64 x, i64 pw){ i64 res = 1; while(pw){ if(pw & 1) res *= x; x *= x; pw >>= 1; } return res; } i64 DP(i64 x, i64 ten, int idx, int pre, int zero, int lim){ if(!idx) return 1; if(dp[idx][pre] != -1 && !zero && !lim) return dp[idx][pre]; int go = (x / ten) % 10; i64 ans = 0; if(!lim) go = 9; for(int my = 0; my <= go; my++){ if(my == pre) continue; if(!my && zero) { ans += DP(x, ten/10, idx-1, 10, 1, lim && (my == go)); } else{ ans += DP(x, ten/10, idx-1, my, 0, lim && (my == go)); } } return dp[idx][pre] = ans; } int check(i64 x, i64 need){ memset(dp, -1, sizeof(dp)); return (DP(x, maxn/10, ma, -1, 1, 1) - 1) < need; } int main() { IOS; int n; i64 k; cin >> n; while(n--){ cin >> k; i64 l = 1, r = (i64)1e18 - 1; while (l != r){ i64 mid = (l + r) >> 1; if(check(mid, k)){ l = mid + 1; } else{ r = mid; } } cout << l << '\n'; } } ``` ### 然後 聽說這題有酷酷數學構造解,如果有人知道怎麼構可以在下方留言,謝謝。