## 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';
}
}
```
### 然後
聽說這題有酷酷數學構造解,如果有人知道怎麼構可以在下方留言,謝謝。