[SOJ #538]好数 [CC]FAVNUM(2019-8-6考试)
题目大意:给定$n$个正整数,求$[l,r]$中第$k$小的”好数“。$l,r\leqslant10^{18},n\leqslant62$,出现的其他数均$\leqslant10^{50}$
好数定义为它至少包含这$n$个数中的一个
题解:二分答案,数位$DP$+$AC$自动机上$DP$,求一个数是第几个好数可以见[文本生成器](https://www.cnblogs.com/Memory-of-winter/p/11305126.html)
卡点:无
C++ Code:
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
const int maxn = 20 * 1000;
long long n, k, l, r;
long long f[20][maxn];
namespace AC {
int nxt[maxn][10], fail[maxn], idx = 1;
bool End[maxn];
void insert(std::string s) {
int p = 1;
for (char ch : s) {
if (nxt[p][ch & 15]) p = nxt[p][ch &15];
else p = nxt[p][ch & 15] = ++idx;
}
End[p] = true;
}
void build() {
std::queue<int> q;
for (int i = 0; i < 10; ++i)
if (nxt[1][i]) fail[nxt[1][i]] = 1, q.push(nxt[1][i]);
else nxt[1][i] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = 0; i < 10; ++i)
if (nxt[u][i]) {
fail[nxt[u][i]] = nxt[fail[u]][i];
End[nxt[u][i]] |= End[fail[nxt[u][i]]];
q.push(nxt[u][i]);
} else nxt[u][i] = nxt[fail[u]][i];
}
}
int num[20], tot;
long long calc(int x, int lim, int lead, int p) {
if (!x) return lead;
long long F = f[x][p];
if (~F && !lim && lead) return F;
F = 0;
for (int i = lim ? num[x] : 9, up = 1; ~i; --i, up = 0)
if (!End[nxt[p][i]])
F += calc(x - 1, lim && up, lead || i, nxt[p][i]);
if (~F && !lim && lead) f[x][p] = F;
return F;
}
long long solve(long long x) {
if (!x) return 0;
long long X = x;
tot = 0;
while (x) num[++tot] = x % 10, x /= 10;
return X - calc(tot, 1, 0, 1);
}
long long query(long long k, long long L, long long R) {
long long base = solve(L - 1), l = L, r = R, ans = L;
while (l <= r) {
long long mid = l + r >> 1, t = solve(mid) - base;
if (t >= k) r = mid - 1, ans = mid;
else l = mid + 1;
}
if (solve(ans) - base != k) return -1;
return ans;
}
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
memset(f, -1, sizeof f);
std::cin >> l >> r >> k >> n;
for (int i = 0; i < n; ++i) {
static std::string s;
std::cin >> s;
AC::insert(s);
}
AC::build();
std::cout << AC::query(k, l, r) << '\n';
return 0;
}

浙公网安备 33010602011771号