From 34135a80152a8a48201704244811c5d55abdc3ea Mon Sep 17 00:00:00 2001 From: Bruno Freitas Tissei <bft15@inf.ufpr.br> Date: Mon, 30 Apr 2018 14:54:14 +0200 Subject: [PATCH] Add fast matrix pow Signed-off-by: Bruno Freitas Tissei <bft15@inf.ufpr.br> --- contests/Cadernaveis/DESCULPA.cpp | 46 ++++++++++++++ contests/Cadernaveis/TOPOLAND.cpp | 102 ++++++++++++++++++++++++++++++ math/fast_matrix_pow.cpp | 63 ++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 contests/Cadernaveis/DESCULPA.cpp create mode 100644 contests/Cadernaveis/TOPOLAND.cpp create mode 100644 math/fast_matrix_pow.cpp diff --git a/contests/Cadernaveis/DESCULPA.cpp b/contests/Cadernaveis/DESCULPA.cpp new file mode 100644 index 0000000..4b05311 --- /dev/null +++ b/contests/Cadernaveis/DESCULPA.cpp @@ -0,0 +1,46 @@ +#include <bits/stdc++.h> + +#define MAX 1010 +#define MOD 1000000007 +#define inf 0x3f3f3f3f + +#define fi first +#define se second +#define sz size() +#define pb push_back +#define ende '\n' +#define all(x) (x).begin(), (x).end() +#define rall(x) (x).rbegin(), (x).rend() + +using namespace std; + +typedef long long ll; +typedef pair<int,int> ii; + +int dp[60][MAX]; +int v[MAX], w[MAX]; + +int main() { + ios::sync_with_stdio(0); + cin.tie(0); + + int c, f, cas = 1; + while (cin >> c >> f && (c || f)) { + memset(dp, 0, sizeof dp); + for (int i = 1; i <= f; ++i) + cin >> w[i] >> v[i]; + + for (int i = 1; i <= f; ++i) + for (int j = 0; j <= c; ++j) + if (j >= w[i]) + dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] + v[i]); + else + dp[i][j] = dp[i-1][j]; + + cout << "Teste " << cas << ende; + cout << dp[f][c] << ende << ende; + cas++; + } + + return 0; +} diff --git a/contests/Cadernaveis/TOPOLAND.cpp b/contests/Cadernaveis/TOPOLAND.cpp new file mode 100644 index 0000000..3db4470 --- /dev/null +++ b/contests/Cadernaveis/TOPOLAND.cpp @@ -0,0 +1,102 @@ +#include <bits/stdc++.h> + +#define MAX 101010 +#define MOD 1000000007 +#define inf 0x3f3f3f3f + +#define fi first +#define se second +#define sz size() +#define pb push_back +#define all(x) (x).begin(), (x).end() +#define rall(x) (x).rbegin(), (x).rend() + +using namespace std; + +typedef long long ll; +typedef pair<int,int> ii; + +ll N, tree[4 * MAX], v[MAX]; + +void build_tree(int node = 1, int a = 0, int b = N) { + if (a > b) + return; + + if (a == b) { + tree[node] = v[a]; + return; + } + + build_tree(node * 2, a, (a + b) / 2); + build_tree(node * 2 + 1, 1 + (a + b) / 2, b); + + tree[node] = max(tree[node * 2], tree[node * 2 + 1]); +} + + +void update_tree(int idx, ll val, int node = 1, int a = 0, int b = N) { + if (a > b || a > idx || b < idx) + return; + + if (a == b) { + tree[node] = val; + return; + } + + update_tree(idx, val, node * 2, a, (a + b) / 2); + update_tree(idx, val, node * 2 + 1, 1 + (a + b) / 2, b); + + tree[node] = max(tree[node * 2], tree[node * 2 + 1]); +} + + +int query_tree(int i, int j, int node = 1, int a = 0, int b = N) { + if (a > b || a > j || b < i) + return 0; + + if (a >= i && b <= j) + return tree[node]; + + int res1 = query_tree(i, j, node * 2, a, (a + b) / 2); + int res2 = query_tree(i, j, node * 2 + 1, 1 + (a + b) / 2, b); + + return max(res1, res2); +} + + +int main() { + ios::sync_with_stdio(0); + cin.tie(0); + + ll t, n, m; + cin >> t; + for (int cas = 0; cas < t; ++cas) { + cout << "Testcase " << cas << ":\n"; + cin >> n >> m; + N = n; + + for (int i = 0; i < n; ++i) + cin >> v[i]; + build_tree(); + + ll q, a, b; + string op; + cin >> q; + for (int i = 0; i < q; ++i) { + cin >> op; + if (op[0] == 'A') { + cin >> a; + m += a; + } else if (op[0] == 'B') { + cin >> a >> b; + update_tree(a, b); + } else { + cin >> a >> b; + cout << abs(m - query_tree(a, b)) << '\n'; + } + } + cout << '\n'; + } + + return 0; +} diff --git a/math/fast_matrix_pow.cpp b/math/fast_matrix_pow.cpp new file mode 100644 index 0000000..c8c02ef --- /dev/null +++ b/math/fast_matrix_pow.cpp @@ -0,0 +1,63 @@ +/** + * Fast Matrix Exponentiation + * + * Complexity (Time): O(K^3 log n) + * Complexity (Space): O(K^2) + */ + +// This algorithm is used to solve recurrences such as: +// f(n) = x1 * f(n - 1) + x2 * f(n - 1) + ... + xk * f(n - k) +// +// It works by defining this recurrence as a linear combination, +// for example (k = 2): +// f(n) = [x1 x2] [f(n - 1)] +// [f(n - 2)] +// It can be rewriten as: +// [ f(n) ] = [x1 x2] [f(n - 1)] +// [f(n - 1)] [ 1 0] [f(n - 2)] +// +// And that is solved by calculating the following matrix power: +// [x1 x2]^n +// [ 1 0] + +#define K 2 + +struct mat { + ll m[K][K]; + + // Matrix multiplication - O(k^3) + mat operator*(mat a) { + mat aux; + + for(int i = 0; i < K; i++) + for(int j = 0; j < K; j++) { + ll sum = 0; + for(int k = 0; k < K; k++) + sum += (m[i][k] * a.m[k][j]) % MOD; + aux.m[i][j] = sum % MOD; + } + + return aux; + } +}; + + +// Fast exponentiation (can be used with integers as well) - O(log n) +ll mat_pow(mat in, ll n) { + mat ans, b = in; + + // Set ans as identity matrix + memset(ans.m, 0, sizeof ans.m); + for (int i = 0; i < K; ++i) + ans.m[i][i] = 1; + + while (n) { + if (n & 1) + ans = ans * b; + + n >>= 1; + b = b * b; + } + + return ans; +} -- GitLab