[SOJ #538]好数 [CC]FAVNUM(2019-8-6考试)

题目大意:给定$n$个正整数,求$[l,r]$中第$k$小的”好数“。$l,rleqslant10^{18},nleqslant62$,出现的其他数均$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) << '
';
	return 0;
}

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/11308834.html