D - Keep Distance 解説 by en_translator
The sequences can be easily sorted in lexicographical order at last, so we will first try to simply enumerate the conforming sequences.
For simplicity of explanation, we regard a sequence good if it is eligible for a prefix (the initial consecutive several terms) of a conforming sequence.
We will consider how to enumerate the good sequences.
A sequence \((A_1)\) of length \(1\) is good if and only if \(1 \leq A_1 \leq M - 10(N - 1)\). (If \(A_1 > M - 10(N - 1)\), then \(A_N\) will exceed \(M\) even if it is at its minimum.)
Suppose that \(2 \leq i \leq N\), and that \((A_1, A_2, \ldots, A_{i - 1})\) is a good sequence. Then, the range of \(A_i\) such that \((A_1, A_2, \ldots, A_{i - 1}, A_i)\) is a good sequence if and only if \(A_{i - 1} + 10 \leq A_i \leq M - 10(N - i)\). (The reason is the same as \(A_1\).)
The problem can be solved by enumerating the good sequences according to this rule.
Since there are at most \(\binom{21}{9} = 293930\) good sequences, this is fast enough if implementation is appropriate. Some implementation may naturally yield good sequences in lexicographical order.
Even without evaluating the number of answers, we can guess that there are not so many conforming sequences, as we are asked to print all of them, and consider that the algorithm will finish within the time limit as long as the number of operations is as large as the number of good sequences.
If you just set the upper bound of \(A_i\) to be \(M\), you will enumerate sequences that can never be a prefix, so it is very unlikely that it finish within the execution time limit.
Sample code
Typical implementation may employ a recursive function, but you may also naively enumerate good sequences of each length.
Non-recursive
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> w = { {} };
for (int i = 1; i <= n; i++) {
vector<vector<int>> v;
for (vector<int> a : w) {
for (int x = (i == 1 ? 1 : a.back() + 10); x <= m - 10 * (n - i); x++) {
vector<int> na = a;
na.push_back(x);
v.push_back(na);
}
}
swap(v, w);
}
int X = w.size();
cout << X << '\n';
for (int i = 0; i < X; i++) for (int j = 0; j < n; j++) cout << w[i][j] << " \n"[j == n - 1];
}
Recursive
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> ans;
auto dfs = [&](auto dfs, vector<int> v) -> void {
int sz = v.size();
if (sz == n) {
ans.push_back(v);
return;
}
for (int i = (sz == 0 ? 1 : v.back() + 10); i <= m - 10 * (n - sz - 1); i++) {
vector<int> nxt = v;
nxt.push_back(i);
dfs(dfs, nxt);
}
};
dfs(dfs, {});
int X = ans.size();
cout << X << '\n';
for (int i = 0; i < X; i++) for (int j = 0; j < n; j++) cout << ans[i][j] << " \n"[j == n - 1];
}
投稿日時:
最終更新: