AtCoder Beginner Contest 009
A
Problem
There are \(n\) boxes, one times can carry \(1\) or \(2\) . What is the mininmu number of carry times.
Solutions
It is must be greedily carrying \(\lceil \frac{n}{2} \rceil = \lfloor \frac{n + 1}{2} \rfloor\) times.
B
Problem
There are \(n\) integers \(a_1, a_2, \cdots, a_n\) , ask for the 2nd largest number in strict partial order. I.e., the 2nd largest number in set \(\mathbb{S} = \{a_1, a_2, \cdots, a_n\}\) . It is guarantee that \(|S| \geq 2\) .
Solutions
- Intuitively, there \(n\) integers need to be added to the \(set\), then push in an array \(b\) of base \(1\) . If \(|b| = m\) , the answer is \(b[m - 1]\) 。The time complexity depends on \(O(n \log n)\) of \(set\) .
int n; std::cin >> n;
std::set<int> S;
for (int i = 1, x; i <= n; i++) {
std::cin >> x;
S.insert(x);
}
std::vector<int> b{S.begin(), S.end()};
b.insert(b.begin(), 0);
int m = b.size() - 1;
std::cout << b[m - 1] << "\n";
-
The solution 1 is equivalent to \(quick\_sort\) as well as \(unique\) . The time complexity depends on \(O(n \log n)\) of \(sort\) , and the time compelexity of \(unique\) is \(O(n)\) .
-
Owing to \(0 \leq a_i \leq 10^{9}\) , Radix sort with a time complexity of \(T(10 n) = O(n)\) can be used. In this way, the time complexity is optimized to \(T(10 n + n) = O(n)\) .
int n; std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; i++) std::cin >> a[i];
auto RadixSort = [&] (std::vector<int> &vec) -> std::vector<int> { // base 1
std::vector<int> a{vec.begin(), vec.end()};
std::vector<int> sa(n + 1), rk(n + 1);
std::vector<int> c(10, 0);
for (int i = 1; i <= n; i++) sa[i] = i;
for (int i = 0, p = 1; i <= 9; i++, p *= 10) {
c.assign(10, 0);
for (int i = 1; i <= n; i++) c[a[sa[i]] / p % 10]++;
for (int i = 1; i <= 9; i++) c[i] += c[i - 1];
for (int i = n; i >= 1; --i) rk[sa[i]] = c[a[sa[i]] / p % 10]--;
for (int i = 1; i <= n; i++) sa[rk[i]] = i;
}
for (int i = 1; i <= n; i++) vec[rk[i]] = a[i];
return vec;
};
RadixSort(a);
a.erase(std::unique(a.begin(), a.end()), a.end());
int m = a.size() - 1;
std::cout << a[m - 1] << "\n";
Let's review the Radix sort of integer!
Countting sort is base on Bucket sort, it is can maintianing the stability of arrays. The time complexity is \(O(n)\) and spatial complexity is \(O(n + M)\) where \(n\) is the size of array and \(m\) is the range of array.
Radix sort is base on Countting sort, it is can maintianing the stability of arrays. The time complexity is \(O(n \log M)\) and spatial complexity is \(O(n + \log M)\) .
We consider \(a_i\) as \(\log M\) keywords \(v_{i_0}, v_{i_1}, \cdots, v_{i_{\log M}}\) such that \(a_i = \overline{v_{i_0} \ v_{i_1} \ \cdots \ v_{i_{\log M}}}\) .
Owing to \(a_i = \overline{v_{i_0} \ v_{i_1} \ \cdots \ v_{i_{\log M}}} = \sum_{i = 0}^{\log M} a_i \times 10^{\log M - i}\) , \(0 \leq v_{i_j} = \lfloor \frac{a_i}{10^{\log M - j}} \rfloor \bmod 10 \leq 9\) .
First we have :
- a map \(sa\) represents the original postion of the sorted array in array \(a\) , at the begining \(sa[i] = i\) .
- a map \(rk\) represents the target postion of th original \(a\) , at the begining the target postion is not eixsts.
- an array \(c\) of size \(10\) represents the number of current keyword.
We traversal \(j\) from \(\log M\) to \(0\) , then we clear the array \(c\) and Bucket sorting \(\forall i, 1 \leq i \leq n, v_{i_{j}}\) , then we got \(c\) and need calculate the prefix sum of the \(c\) , e.g. \(For\ i\ 1\ from\ to\ 9, c[i] = c[i] + c[i - 1]\) .
For the sorted array, \(For\ i\ from\ n\ to\ 1, rk[sa[i]] = c[sa[v_{i_{j}}]]--\) .
For the traget array, \(For\ i\ from\ 1\ to\ n, sa[rk[i]] = i\) .
C
Problem
Given a string \(S\) constisting lowercase letters of length \(N\) , find the string with the smallest lexicographic order obtained by changing the postion of at most \(K\) characters.
Solutions
Firstly, Du to the need to impletement mininmu lexicographic order, a greedy algorithm is evident. Here is its pseudo code :
T <- ""
for i = 1 to N
for c in ( unused characters sorted in ascending order )
if ( the number of postion changed in (T + c + an arrangement of unused characters after ruducing one c) <= k )
T <- T + c
break
This is a calssic greedy problem model.
\(i\) represents the current length of string \(T\) . Because \(T\) is as least exists, the loop can run.
We just need to implement two implementations :
- travesal c in ( unused characters sorted in ascending order )
- check if ( the mininmu number of postion changed in (T + c + an arrangement of unused characters after ruducing one c) <= k )
In the first impletmentation. Due to the fact that there are only 26 types of characters and each types only needs to be judged onece, we just need travesal \(c\) from 'a' to 'z' and check if the counter of \(c\) in the unused characters is greater than \(0\) .
for i = 0 to 26 - 1
if (rem[i] in (unuset characters sorted in ascending order) > 0)
The time complexity is \(O(\varepsilon)\) . \(\varepsilon\) is the character set size, which is \(26\) .
In the second impletmentaiton.
- The number of postion changed in \(S_1 \sim S_{i - 1}\) is fixed, we can maintain as \(Bad\) .
- The number of postion changed in \(S_[i]\) is fixed and it is \([c \neq S_i]\) .
- For the number of postion changed in \(S_{i + 1} \sim S_{n}\) , we just calculte the mininmu number and the number is :\[ v = S.length() - i - \sum_{x - 'a' = 0}^{25} min(\textbf{the counter of} \ x \ \textbf{in the unused characters after ruducing one} \ c \ , \ \textbf{the counter of} \ x \ \textbf{in the substring} \ string(S_{i + 1} \sim S_{i}) \ \textbf{of} \ S) \]if \(Bad + [c \neq S_i] + v \leq k\) , we can selcete \(c\) , execute \(T \leftarrow T + c\) and break the travesal of \(c\) . The time complexity is \(O(\varepsilon)\) .
We can maintain the counter of \(x\) in the substring \(S_{i + 1} \sim S_{n}\) of \(S\) . E.g., we can use \(rem1\) , then execute operation \(rem1[S_i]--\) when \(i\) is travsaled.
We can maintian the counter of \(x\) in the unused characters after ruducing one \(c\) . E.g., we can use \(rem2\) , then execute operation \(rem2[c]--, T \leftarrow T + c\) when \(c\) is fixed and execute operation \(rem2[c]++, T \leftarrow T.pop\_back()\) when \(c\) is skipped. Obviously if \(c\) is selected, it will not be skipped, and we maintain \(Bad \leftarrow Bad + [S_i \neq c]\) .
So we can use an algorithm with a total time complexity of \(O(N \varepsilon^{2})\) to solve the problem.
view
int N, K; std::cin >> N >> K;
std::string S; std::cin >> S; S = " " + S;
int rem1[26] = {0}, rem2[26] = {0};
for (int i = 1; i <= N; i++) rem2[int(S[i] - 'a')] = ++rem1[int(S[i] - 'a')];
int Bad = 0;
std::string T = " ";
for (int i = 1; i <= N; i++) {
rem1[int(S[i] - 'a')]--;
for (int j = 0; j < 26; j++) if (rem2[j] > 0) {
rem2[j]--;
T.push_back(char(j + 'a'));
int v = N - i;
for (int k = 0; k < 26; k++) if (rem2[k] > 0) {
v -= std::min(rem1[k], rem2[k]);
}
int curBad = Bad + (S[i] != T[i]) + v;
if (curBad <= K) {
assert(T.size() - 1 == i);
Bad += (T[i] != S[i]);
break;
}
T.pop_back();
rem2[j]++;
}
}
T.erase(0, 1);
std::cout << T << "\n";
D
Problem
The elements of sequence \(A\) are 32-bit unsigned integers. (\(\bmod 2^{32}\))
Given the first \(K\) terms \(A_1, A_2, A_3, \cdots, A_K\) of sequence \(A\) , and \(C_1, C_2, C_3, \cdots, C_K\) of a sequence \(C\) with \(K\) terms which elements are 32-bit unsigned integers.
For \(N \geq 1\) :
\(And\) stands for bitwise logical conjunction and \(XOR\) stands for bitwise exclusive or.
You need to answer what is \(A_{M}\) .
\(1 \leq K \leq 100, 1 \leq M \leq 10^{9}\) .
Solutions
When each term in the sequence is determined by the preceding term(without cycle), recursion is an equation for calculating this term.
E.g., \(F_{n + 2} = F_{n + 1} + F_{n}\) is a classic recursion, its initial value is \(F_{0} = 1, F_{1} = 1\) .
How to calculate \(F_{n}\)?
- We can just use \(F_{n + 2} = F_{n + 1} + F_{n}\) which time complextiy is \(O(n)\) .
- We can use matrix to quickly calculate it with time complexity \(O(w^{3} \log n)\). \(w\) is the size of matrix also the number of terms in the recursion.
Observe :
We can design a matrix \(v\) that satisfies :
Evidently, there is a matrix
so that
Then, we have
Owing to matrix multiplication of \(C_{n, k} = A_{n, m} \cdot B_{m, k}\) is
the time complextiy of matrix multiplication is \(O(nmk)\) , and the complextiy of \(v^{N}\) is \(O(w^{3} \log N)\) .
This is an efficient algorithm for calculating \(F_{N + 2} = F_{N + 1} + F_{N}\) .
But, can all recursion be quickly calculated using matrix?
- \(F_{N + 2} = F_{N + 1} + F_{N}^{2}\) . If there are two preceding terms muliplied, we can't quickly calclulated recursion using matrix.
- \(F_{N + 2} = aF_{N + 1} + bF_{N}\) . If it is homogeneous form like \(F_{N} = \sum_{j < i} (\textbf{constant term} \ C) \ \cdot (\textbf{preceding term} \ F_j \ \textbf{of recursion})\) . It can be quickly calclated by using matrix.
However, the most important point is that for a homogeneous recursion \(F\) , if we consider it as a ring \(<\mathbb{G}, +, \cdot>\) and its a semisimple ring, we also can quickly calculated the recursion by using matrix.
A semisimple ring \(<\mathbb{G}, +, \cdot>\) is that :
- \(<\mathbb{G}, +>\) is a monoid that satisfies the commutativty (We can see a monoid as a semigroup with indentity element).
- if \(<\mathbb{G}, +>\) is an Abelian group and satisfied the following conditions, \(<\mathbb{G}, +, \cdot>\) is an ring.
- \(<\mathbb{G}, \cdot>\) is a semigroup.
- \(\cdot\) and \(+\) satisfied the law of distribution \(\forall a, b, c \in \mathbb{G}, \ a \cdot (b + c) = a \cdot b + a \cdot c\) .
For
we can rewrite as
First of all recursion \(A_{N + K} = \bigoplus_{i = 1}^{K} C_i \odot A_{N + K - i}\) is homogeneous, then \(<\mathbb{G}, \oplus, \odot>\) is a semigroup while \(\mathbb{G}\) is the set of 32-bit unsigned integer. So we can quickly calculated \(A_{M}\) by using matrix.
Befor doing this, let's see how to find the transitin matrix \(v\) of \(F_{N + 2} = a F_{N + 1} + b F_{N}\) .
We construct a matrix \(v\) as
so that satisfied
we have
Then we trying to calculate \(A_{N + K} = \bigoplus_{i = 1}^{K} C_i \odot A_{N + K - i}\) .
we can design a matrix \(v\) satisfied that
At long last, we just calculate
by using matirix quickly pow as well as rewrite the matrix multiplication and the identity element of matrix \(v\) .
- For the matrix multiplication of \(C_{n, k} = A_{n, m} \times B_{m, k}\), we jsut
- For the identity element of matrix \(v\) , obviously \(\underbrace{111\cdots1}_{32} \odot v = v\) , we can just use \(std::numeric\_limits<u32>::max()\) or \(-u32(1)\) to get it.
- Howerver we can confirm that this matrix is definitely irreversible becaues \(<\mathbb{G}, \oplus, \odot>\) is a semisimple ring.
view
template<typename T /*, const int MOD = int(1E9)+7*/>
struct Matrix {
std::vector<std::vector<T> > a;
int n, m;
Matrix () {}
Matrix (int n, int m) { init(n, m); }
void init (int n, int m) {
this->n = n;
this->m = m;
a.resize(n + 1);
for (auto &u : a) u.resize(m + 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = 0;
}
void set(int i, int j, T v) {
a[i][j] = v;
}
T& get(int i, int j) {
return a[i][j];
}
void setI() {
assert(n == m);
for (int i = 1; i <= n; i++) a[i][i] = 1;
}
Matrix operator * (Matrix<T> &V) {
assert(this->m == V.n);
int n = this->n, m = this->m, k = V.m;
Matrix<T> res(n, k);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) {
for (int l = 1; l <= m; l++) {
res.get(i, j) ^= (this->a[i][l] & V.get(l, j));// % MOD;
// res.get(i, j) %= MOD;
}
}
}
return res;
}
Matrix Tran() {
Matrix vt(m, n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
vt.set(j, i, a[i][j]);
}
}
return vt;
}
void print() {
std::cout << "\nmatrix as\n";
std::string line = std::string(20, '-');
std::cout << line << "\n";
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
std::cout << get(i, j) << " \n"[j == m];
}
}
std::cout << line << "\n\n";
}
};
Matrix<u32> Mksm(Matrix<u32> a, i64 pw) {
int n = a.n, m = a.m;
assert(n == m);
Matrix<u32> res(n, n);
for (int i = 1; i <= n; i++) res.set(i, i, -u32(1));
for ( ;pw; pw>>=1, a = a * a) if (pw & 1)
res = res * a;
return res;
}
// ~~ SEG END
void solve() {
int K, M; std::cin >> K >> M;
std::vector<u32> A(K + 1);
std::vector<u32> C(K + 1);
for (int i = 1; i <= K; i++) std::cin >> A[i];
for (int i = 1; i <= K; i++) std::cin >> C[i];
Matrix<u32> v(K, K);
Matrix<u32> f(K, 1);
for (int i = 1; i <= K; i++) {
f.set(i, 1, A[i]);
for (int j = 1; j <= K; j++) {
if (i < K) {
if (j != i + 1) v.set(i, j, 0);
else v.set(i, j, -u32(1));
} else {
v.set(i, j, C[K - j + 1]);
}
}
}
// v.print(); f.print();
// Mksm(v, 4).print();
f = Mksm(v, M - 1) * f;
std::cout << f.get(1, 1) << "\n";
}
Finally, did you discover how to construct the transtion matrix?
For a matrix \(V\) which elements in the i-th row and the j-th is \(v_{i, j}\) satisfied
We can just make sure that \(\sum_{j = 1}^{j = N} v_{i, j} \times F_{j} = F_{i + 1}\) 。
浙公网安备 33010602011771号