CodeForces 1845C Strong Password

发布时间 2023-06-30 23:15:04作者: zltzlt

洛谷传送门

CF 传送门

我怎么这么多天没写题解了,快来水一篇。

考虑对 \(s\) 串建子序列自动机后 dp。

\(n = |s|\)。建子序列自动机,就是求出 \(nxt_{i, j}\)\([i, n]\) 中第一个等于 \(j\) 的位置,不存在则 \(nxt_{i, j} = n + 1\)

然后我们设 \(f_{i, j}\) 为填到密码的第 \(i\) 位,当前匹配到 \(s\) 串的第 \(j\) 位是否存在。注意我们贪心匹配最前能匹配的位置。注意如果 \(j = n + 1\) 说明匹配不完,即密码已经不是一个 \(s\) 的子序列。

转移枚举当前位填的数位 \(d\),根据子序列自动机可以求得 \([j + 1, n]\) 中第一个 \(d\) 的出现位置,就能转移了。

答案是 \(f_{m, n + 1}\)

code
// Problem: C. Strong Password
// Contest: Codeforces - Educational Codeforces Round 151 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1845/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 300100;

int n, m, nxt[maxn][11], f[11][maxn];
char s[maxn], a[maxn], b[maxn];

void solve() {
	scanf("%s%d%s%s", s + 1, &m, a + 1, b + 1);
	n = strlen(s + 1);
	for (int i = 0; i < 10; ++i) {
		nxt[n + 1][i] = n + 1;
	}
	for (int i = n; i; --i) {
		for (int j = 0; j < 10; ++j) {
			nxt[i][j] = nxt[i + 1][j];
		}
		nxt[i][s[i] - '0'] = i;
	}
	for (int i = 0; i <= m; ++i) {
		for (int j = 0; j <= n + 1; ++j) {
			f[i][j] = 0;
		}
	}
	f[0][0] = 1;
	for (int i = 1; i <= m; ++i) {
		for (int j = 0; j <= n + 1; ++j) {
			if (f[i - 1][j]) {
				for (int k = a[i] - '0'; k <= b[i] - '0'; ++k) {
					f[i][j == n + 1 ? n + 1 : nxt[j + 1][k]] = 1;
				}
			}
		}
	}
	puts(f[m][n + 1] ? "YES" : "NO");
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}