├── Berlekamp-Massey.cpp ├── Berlekamp-Massey_Test.cpp ├── Black Box Linear Algebra.pdf ├── Black Box Linear Algebra.pptx ├── Construction Problems.pdf ├── Construction Problems.pptx ├── How to AC it.pdf ├── How to AC it.pptx ├── LinearRecurrence.cpp ├── LinearRecurrence_Test1.cpp ├── LinearRecurrence_Test2.cpp ├── MatrixDeterminant_Test.cpp ├── MatrixMultiplication_Test.cpp └── README.md /Berlekamp-Massey.cpp: -------------------------------------------------------------------------------- 1 | // Berlekamp-Massey Algorithm 2 | // Complexity: O(n^2) 3 | // Requirement: const MOD, inverse(int) 4 | // Input: vector - the first elements of the sequence 5 | // Output: vector - the recursive equation of the given sequence 6 | // Example: In: {1, 1, 2, 3} Out: {1, 1000000006, 1000000006} (MOD = 1e9+7) 7 | 8 | struct Poly { 9 | vector a; 10 | 11 | Poly() { a.clear(); } 12 | 13 | Poly(vector &a): a(a) {} 14 | 15 | int length() const { return a.size(); } 16 | 17 | Poly move(int d) { 18 | vector na(d, 0); 19 | na.insert(na.end(), a.begin(), a.end()); 20 | return Poly(na); 21 | } 22 | 23 | int calc(vector &d, int pos) { 24 | int ret = 0; 25 | for (int i = 0; i < (int)a.size(); ++i) { 26 | if ((ret += (long long)d[pos - i] * a[i] % MOD) >= MOD) { 27 | ret -= MOD; 28 | } 29 | } 30 | return ret; 31 | } 32 | 33 | Poly operator - (const Poly &b) { 34 | vector na(max(this->length(), b.length())); 35 | for (int i = 0; i < (int)na.size(); ++i) { 36 | int aa = i < this->length() ? this->a[i] : 0, 37 | bb = i < b.length() ? b.a[i] : 0; 38 | na[i] = (aa + MOD - bb) % MOD; 39 | } 40 | return Poly(na); 41 | } 42 | }; 43 | 44 | Poly operator * (const int &c, const Poly &p) { 45 | vector na(p.length()); 46 | for (int i = 0; i < (int)na.size(); ++i) { 47 | na[i] = (long long)c * p.a[i] % MOD; 48 | } 49 | return na; 50 | } 51 | 52 | vector solve(vector a) { 53 | int n = a.size(); 54 | Poly s, b; 55 | s.a.push_back(1), b.a.push_back(1); 56 | for (int i = 1, j = 0, ld = a[0]; i < n; ++i) { 57 | int d = s.calc(a, i); 58 | if (d) { 59 | if ((s.length() - 1) * 2 <= i) { 60 | Poly ob = b; 61 | b = s; 62 | s = s - (long long)d * inverse(ld) % MOD * ob.move(i - j); 63 | j = i; 64 | ld = d; 65 | } else { 66 | s = s - (long long)d * inverse(ld) % MOD * b.move(i - j); 67 | } 68 | } 69 | } 70 | //Caution: s.a might be shorter than expected 71 | return s.a; 72 | } 73 | -------------------------------------------------------------------------------- /Berlekamp-Massey_Test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int MOD = 1000000007; 10 | 11 | int inverse(int a) { 12 | return a == 1 ? 1 : (long long)(MOD - MOD / a) * inverse(MOD % a) % MOD; 13 | } 14 | 15 | // Berlekamp-Massey Algorithm 16 | // Requirement: const MOD, inverse(int) 17 | // Input: vector the first elements of the sequence 18 | // Output: vector the recursive equation of the given sequence 19 | // Example: In: {1, 1, 2, 3} Out: {1, 1000000006, 1000000006} (MOD = 1e9+7) 20 | 21 | struct Poly { 22 | vector a; 23 | 24 | Poly() { a.clear(); } 25 | 26 | Poly(vector &a): a(a) {} 27 | 28 | int length() const { return a.size(); } 29 | 30 | Poly move(int d) { 31 | vector na(d, 0); 32 | na.insert(na.end(), a.begin(), a.end()); 33 | return Poly(na); 34 | } 35 | 36 | int calc(vector &d, int pos) { 37 | int ret = 0; 38 | for (int i = 0; i < (int)a.size(); ++i) { 39 | if ((ret += (long long)d[pos - i] * a[i] % MOD) >= MOD) { 40 | ret -= MOD; 41 | } 42 | } 43 | return ret; 44 | } 45 | 46 | Poly operator - (const Poly &b) { 47 | vector na(max(this->length(), b.length())); 48 | for (int i = 0; i < (int)na.size(); ++i) { 49 | int aa = i < this->length() ? this->a[i] : 0, 50 | bb = i < b.length() ? b.a[i] : 0; 51 | na[i] = (aa + MOD - bb) % MOD; 52 | } 53 | return Poly(na); 54 | } 55 | }; 56 | 57 | Poly operator * (const int &c, const Poly &p) { 58 | vector na(p.length()); 59 | for (int i = 0; i < (int)na.size(); ++i) { 60 | na[i] = (long long)c * p.a[i] % MOD; 61 | } 62 | return na; 63 | } 64 | 65 | vector solve(vector a) { 66 | int n = a.size(); 67 | Poly s, b; 68 | s.a.push_back(1), b.a.push_back(1); 69 | for (int i = 1, j = 0, ld = a[0]; i < n; ++i) { 70 | int d = s.calc(a, i); 71 | if (d) { 72 | if ((s.length() - 1) * 2 <= i) { 73 | Poly ob = b; 74 | b = s; 75 | s = s - (long long)d * inverse(ld) % MOD * ob.move(i - j); 76 | j = i; 77 | ld = d; 78 | } else { 79 | s = s - (long long)d * inverse(ld) % MOD * b.move(i - j); 80 | } 81 | } 82 | } 83 | return s.a; 84 | } 85 | 86 | //end of template 87 | 88 | int main() { 89 | int T = 1000; 90 | for (int i = 0; i < T; ++i) { 91 | cout << "Test " << i + 1 << endl; 92 | int n = rand() % 1000 + 1; 93 | vector s; 94 | for (int i = 0; i < n; ++i) { 95 | s.push_back(rand() % (MOD - 1) + 1); 96 | } 97 | vector a; 98 | for (int i = 0; i < n; ++i) { 99 | a.push_back(rand() % MOD); 100 | } 101 | for (int i = 0; i < n; ++i) { 102 | int na = 0; 103 | for (int j = 0; j < n; ++j) { 104 | if ((na += (long long)a[n + i - 1 - j] * s[j] % MOD) >= MOD) { 105 | na -= MOD; 106 | } 107 | } 108 | a.push_back(na); 109 | } 110 | vector ss = solve(a); 111 | /* 112 | for (int i = 0; i < n; ++i) { 113 | printf("%d%c", s[i], i == n - 1 ? '\n' : ' '); 114 | } 115 | cout << endl; 116 | for (int i = 0; i < n; ++i) { 117 | printf("%d%c", ss[i + 1], i == n - 1 ? '\n' : ' '); 118 | } 119 | */ 120 | assert((int)ss.size() == n + 1); 121 | assert(ss[0] == 1); 122 | for (int i = 0; i < n; ++i) { 123 | assert((ss[i + 1] + s[i]) % MOD == 0); 124 | } 125 | } 126 | cout << "All tests OK!!!" << endl; 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /Black Box Linear Algebra.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICPCCamp/BlackBoxLinearAlgebra/f7c6ad9387aecb6861ef562245fd3ab2bcd5160b/Black Box Linear Algebra.pdf -------------------------------------------------------------------------------- /Black Box Linear Algebra.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICPCCamp/BlackBoxLinearAlgebra/f7c6ad9387aecb6861ef562245fd3ab2bcd5160b/Black Box Linear Algebra.pptx -------------------------------------------------------------------------------- /Construction Problems.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICPCCamp/BlackBoxLinearAlgebra/f7c6ad9387aecb6861ef562245fd3ab2bcd5160b/Construction Problems.pdf -------------------------------------------------------------------------------- /Construction Problems.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICPCCamp/BlackBoxLinearAlgebra/f7c6ad9387aecb6861ef562245fd3ab2bcd5160b/Construction Problems.pptx -------------------------------------------------------------------------------- /How to AC it.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICPCCamp/BlackBoxLinearAlgebra/f7c6ad9387aecb6861ef562245fd3ab2bcd5160b/How to AC it.pdf -------------------------------------------------------------------------------- /How to AC it.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ICPCCamp/BlackBoxLinearAlgebra/f7c6ad9387aecb6861ef562245fd3ab2bcd5160b/How to AC it.pptx -------------------------------------------------------------------------------- /LinearRecurrence.cpp: -------------------------------------------------------------------------------- 1 | // Calculating kth term of linear recurrence sequence 2 | // Complexity: init O(n^2log) query O(n^2logk) 3 | // Requirement: const LOG const MOD 4 | // Input(constructor): vector - first n terms 5 | // vector - transition function 6 | // Output(calc(k)): int - the kth term mod MOD 7 | // Example: In: {1, 1} {2, 1} an = 2an-1 + an-2 8 | // Out: calc(3) = 3, calc(10007) = 71480733 (MOD 1e9+7) 9 | 10 | struct LinearRec { 11 | 12 | int n; 13 | vector first, trans; 14 | vector > bin; 15 | 16 | vector add(vector &a, vector &b) { 17 | vector result(n * 2 + 1, 0); 18 | //You can apply constant optimization here to get a ~10x speedup 19 | for (int i = 0; i <= n; ++i) { 20 | for (int j = 0; j <= n; ++j) { 21 | if ((result[i + j] += (long long)a[i] * b[j] % MOD) >= MOD) { 22 | result[i + j] -= MOD; 23 | } 24 | } 25 | } 26 | for (int i = 2 * n; i > n; --i) { 27 | for (int j = 0; j < n; ++j) { 28 | if ((result[i - 1 - j] += (long long)result[i] * trans[j] % MOD) >= MOD) { 29 | result[i - 1 - j] -= MOD; 30 | } 31 | } 32 | result[i] = 0; 33 | } 34 | result.erase(result.begin() + n + 1, result.end()); 35 | return result; 36 | } 37 | 38 | LinearRec(vector &first, vector &trans):first(first), trans(trans) { 39 | n = first.size(); 40 | vector a(n + 1, 0); 41 | a[1] = 1; 42 | bin.push_back(a); 43 | for (int i = 1; i < LOG; ++i) { 44 | bin.push_back(add(bin[i - 1], bin[i - 1])); 45 | } 46 | } 47 | 48 | int calc(int k) { 49 | vector a(n + 1, 0); 50 | a[0] = 1; 51 | for (int i = 0; i < LOG; ++i) { 52 | if (k >> i & 1) { 53 | a = add(a, bin[i]); 54 | } 55 | } 56 | int ret = 0; 57 | for (int i = 0; i < n; ++i) { 58 | if ((ret += (long long)a[i + 1] * first[i] % MOD) >= MOD) { 59 | ret -= MOD; 60 | } 61 | } 62 | return ret; 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /LinearRecurrence_Test1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int LOG = 31, MOD = 1000000007; 9 | 10 | // Calculating kth term of linear recurrence sequence 11 | // Complexity: init O(n^2log) query O(n^2logk) 12 | // Requirement: const LOG const MOD 13 | // Input(constructor): vector - first n terms 14 | // vector - transition function 15 | // Output(calc(k)): int - the kth term mod MOD 16 | // Example: In: {1, 1} {2, 1} an = 2an-1 + an-2 17 | // Out: calc(3) = 3, calc(10007) = 71480733 (MOD 1e9+7) 18 | 19 | struct LinearRec { 20 | 21 | int n; 22 | vector first, trans; 23 | vector > bin; 24 | 25 | vector add(vector &a, vector &b) { 26 | vector result(n * 2 + 1, 0); 27 | //You can apply constant optimization here to get a ~10x speedup 28 | for (int i = 0; i <= n; ++i) { 29 | for (int j = 0; j <= n; ++j) { 30 | if ((result[i + j] += (long long)a[i] * b[j] % MOD) >= MOD) { 31 | result[i + j] -= MOD; 32 | } 33 | } 34 | } 35 | for (int i = 2 * n; i > n; --i) { 36 | for (int j = 0; j < n; ++j) { 37 | if ((result[i - 1 - j] += (long long)result[i] * trans[j] % MOD) >= MOD) { 38 | result[i - 1 - j] -= MOD; 39 | } 40 | } 41 | result[i] = 0; 42 | } 43 | result.erase(result.begin() + n + 1, result.end()); 44 | return result; 45 | } 46 | 47 | LinearRec(vector &first, vector &trans):first(first), trans(trans) { 48 | n = first.size(); 49 | vector a(n + 1, 0); 50 | a[1] = 1; 51 | bin.push_back(a); 52 | for (int i = 1; i < LOG; ++i) { 53 | bin.push_back(add(bin[i - 1], bin[i - 1])); 54 | } 55 | } 56 | 57 | int calc(int k) { 58 | vector a(n + 1, 0); 59 | a[0] = 1; 60 | for (int i = 0; i < LOG; ++i) { 61 | if (k >> i & 1) { 62 | a = add(a, bin[i]); 63 | } 64 | } 65 | int ret = 0; 66 | for (int i = 0; i < n; ++i) { 67 | if ((ret += (long long)a[i + 1] * first[i] % MOD) >= MOD) { 68 | ret -= MOD; 69 | } 70 | } 71 | return ret; 72 | } 73 | }; 74 | 75 | //end of template 76 | 77 | //test on http://tdpc.contest.atcoder.jp/tasks/tdpc_fibonacci 78 | 79 | int n, k; 80 | 81 | int main() { 82 | scanf("%d%d", &n, &k); 83 | vector a(n, 1); 84 | LinearRec f(a, a); 85 | printf("%d\n", f.calc(k)); 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /LinearRecurrence_Test2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const unsigned LOG = 31; 9 | 10 | // Calculating kth term of linear recurrence sequence 11 | // Modified for testing 12 | 13 | struct LinearRec { 14 | 15 | int n; 16 | vector first, trans; 17 | vector > bin; 18 | 19 | vector add(vector &a, vector &b) { 20 | vector result(n * 2 + 1, 0); 21 | for (int i = 0; i <= n; ++i) { 22 | for (int j = 0; j <= n; ++j) { 23 | result[i + j] ^= a[i] & b[j]; 24 | } 25 | } 26 | for (int i = 2 * n; i > n; --i) { 27 | for (int j = 0; j < n; ++j) { 28 | result[i - 1 - j] ^= result[i] & trans[j]; 29 | } 30 | result[i] = 0; 31 | } 32 | result.erase(result.begin() + n + 1, result.end()); 33 | return result; 34 | } 35 | 36 | LinearRec(vector &first, vector &trans):first(first), trans(trans) { 37 | n = first.size(); 38 | vector a(n + 1, 0); 39 | a[1] = ~0u; 40 | bin.push_back(a); 41 | for (int i = 1; i < LOG; ++i) { 42 | bin.push_back(add(bin[i - 1], bin[i - 1])); 43 | } 44 | } 45 | 46 | unsigned calc(int k) { 47 | vector a(n + 1, 0); 48 | a[0] = ~0u; 49 | for (int i = 0; i < LOG; ++i) { 50 | if (k >> i & 1) { 51 | a = add(a, bin[i]); 52 | } 53 | } 54 | unsigned ret = 0; 55 | for (int i = 0; i < n; ++i) { 56 | ret = ret ^ (a[i + 1] & first[i]); 57 | } 58 | return ret; 59 | } 60 | }; 61 | 62 | //end of template 63 | 64 | //test on http://abc009.contest.atcoder.jp/tasks/abc009_4 65 | 66 | int n, k; 67 | 68 | int main() { 69 | scanf("%d%d", &n, &k); 70 | vector a(n), b(n); 71 | for (int i = 0; i < n; ++i) { 72 | scanf("%u", &a[i]); 73 | } 74 | for (int i = 0; i < n; ++i) { 75 | scanf("%u", &b[i]); 76 | } 77 | LinearRec f(a, b); 78 | printf("%u\n", f.calc(k)); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /MatrixDeterminant_Test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int MOD = 1000000007, N = 10005, M = N * 11; 9 | 10 | const int BAR = 10; 11 | 12 | struct Vector { 13 | int n, a[N]; 14 | 15 | Vector(int n):n(n) { 16 | memset(a, 0, sizeof(a)); 17 | } 18 | 19 | int& operator[] (const int &i) { return a[i]; } 20 | const int operator[] (const int &i) const { return a[i]; } 21 | 22 | int operator * (const Vector &b) { 23 | unsigned long long ret = 0; 24 | for (int i = 0; i < n; ++i) { 25 | for (int j = 0; j < BAR && i < n; ++j, ++i) { 26 | ret = ret + (unsigned long long)a[i] * b[i]; 27 | } 28 | --i; 29 | ret %= MOD; 30 | } 31 | return ret; 32 | } 33 | 34 | }; 35 | 36 | struct Matrix { 37 | int n, m; 38 | int x[M], y[M], a[M]; 39 | 40 | Matrix(int n):n(n) { 41 | m = 0; 42 | memset(a, 0, sizeof(a)); 43 | } 44 | 45 | void reshuffle() { 46 | vector > > v(m); 47 | for (int i = 0; i < m; ++i) { 48 | v[i].first = x[i], v[i].second.first = y[i], v[i].second.second = a[i]; 49 | } 50 | sort(v.begin(), v.end()); 51 | for (int i = 0; i < m; ++i) { 52 | x[i] = v[i].first, y[i] = v[i].second.first, a[i] = v[i].second.second; 53 | } 54 | } 55 | 56 | Vector operator * (const Vector &b) const { 57 | Vector ret(n); 58 | for (int i = 0; i < m; ++i) { 59 | if ((ret[x[i]] += (unsigned long long)a[i] * b[y[i]] % MOD) >= MOD) { 60 | ret[x[i]] -= MOD; 61 | } 62 | } 63 | return ret; 64 | } 65 | }; 66 | 67 | unsigned long long buf[N]; 68 | 69 | void mul(const Matrix &A, Vector &b) { //to save memory 70 | int n = A.n; 71 | memset(buf, 0, sizeof(unsigned long long) * n); 72 | 73 | for (int i = 0; i < A.m; ++i) { 74 | buf[A.x[i]] += (unsigned long long)A.a[i] * b[A.y[i]]; 75 | if (i % BAR == 0) { 76 | buf[A.x[i]] %= MOD; 77 | } 78 | } 79 | 80 | for (int i = 0; i < A.n; ++i) { 81 | b[i] = buf[i] % MOD; 82 | } 83 | } 84 | 85 | // Berlekamp-Massey Algorithm 86 | 87 | int inverse(int a) { 88 | return a == 1 ? 1 : (long long)(MOD - MOD / a) * inverse(MOD % a) % MOD; 89 | } 90 | 91 | vector na; 92 | 93 | struct Poly { 94 | vector a; 95 | 96 | Poly() { a.clear(); } 97 | 98 | Poly(vector &a): a(a) {} 99 | 100 | int length() const { return a.size(); } 101 | 102 | Poly move(int d) { 103 | na.resize(d + a.size()); 104 | for (int i = 0; i < d + a.size(); ++i) { 105 | na[i] = i < d ? 0 : a[i - d]; 106 | } 107 | return na; 108 | } 109 | 110 | int calc(vector &d, int pos) { 111 | unsigned long long ret = 0; 112 | for (int i = 0; i < (int)a.size(); ++i) { 113 | for (int j = 0; j < BAR && i < (int)a.size(); ++j, ++i) { 114 | ret = ret + (unsigned long long)d[pos - i] * a[i]; 115 | } 116 | --i; 117 | ret %= MOD; 118 | } 119 | return ret; 120 | } 121 | 122 | Poly operator - (const Poly &b) { 123 | na.resize(max(this->length(), b.length())); 124 | for (int i = 0; i < (int)na.size(); ++i) { 125 | int aa = i < this->length() ? this->a[i] : 0, 126 | bb = i < b.length() ? b.a[i] : 0; 127 | na[i] = aa >= bb ? aa - bb : aa + MOD - bb; 128 | } 129 | return Poly(na); 130 | } 131 | }; 132 | 133 | Poly operator * (const int &c, const Poly &p) { 134 | na.resize(p.length()); 135 | for (int i = 0; i < (int)na.size(); ++i) { 136 | na[i] = (long long)c * p.a[i] % MOD; 137 | } 138 | return na; 139 | } 140 | 141 | vector Berlekamp(vector a) { 142 | int n = a.size(); 143 | Poly s, b; 144 | s.a.push_back(1), b.a.push_back(1); 145 | for (int i = 1, j = 0, ld = a[0]; i < n; ++i) { 146 | int d = s.calc(a, i); 147 | if (d) { 148 | if ((s.length() - 1) * 2 <= i) { 149 | Poly ob = b; 150 | b = s; 151 | s = s - (long long)d * inverse(ld) % MOD * ob.move(i - j); 152 | j = i; 153 | ld = d; 154 | } else { 155 | s = s - (long long)d * inverse(ld) % MOD * b.move(i - j); 156 | } 157 | } 158 | } 159 | return s.a; 160 | } 161 | 162 | Vector getRandomVector(int n) { 163 | Vector ret(n); 164 | for (int i = 0; i < n; ++i) { 165 | ret[i] = rand() % MOD; 166 | } 167 | return ret; 168 | } 169 | 170 | int solve(Matrix &A) { 171 | Vector d = getRandomVector(A.n), x = getRandomVector(A.n), y = getRandomVector(A.n); 172 | for (int i = 0; i < A.m; ++i) { 173 | A.a[i] = (long long)A.a[i] * d[A.x[i]] % MOD; 174 | } 175 | vector a; 176 | for (int i = 0; i < A.n * 2 + 1; ++i) { 177 | mul(A, x); //x = A * x; 178 | a.push_back(x * y); 179 | } 180 | vector s = Berlekamp(a); 181 | int ret = s.back(); 182 | if (A.n & 1) { 183 | ret = (MOD - ret) % MOD; 184 | } 185 | for (int i = 0; i < A.n; ++i) { 186 | ret = (long long)ret * inverse(d[i]) % MOD; 187 | } 188 | return ret; 189 | } 190 | 191 | //tested on CF 348F - Little Artem and Graph 192 | 193 | int n, k; 194 | 195 | void initMatrix(Matrix &A) { 196 | A.m = n - 1; 197 | for (int i = 0; i < n - 1; ++i) { 198 | A.x[i] = A.y[i] = i; 199 | A.a[i] = 0; 200 | } 201 | } 202 | 203 | void addEdge(Matrix &A, int u, int v) { 204 | if (u < A.n && v < A.n) { 205 | A.x[A.m] = u, A.y[A.m] = v, A.a[A.m] = MOD - 1, ++A.m; 206 | A.x[A.m] = v, A.y[A.m] = u, A.a[A.m] = MOD - 1, ++A.m; 207 | } 208 | if (u < A.n) { 209 | ++A.a[u]; 210 | } 211 | if (v < A.n) { 212 | ++A.a[v]; 213 | } 214 | } 215 | 216 | int main() { 217 | scanf("%d%d", &n, &k); 218 | Matrix A(n - 1); 219 | initMatrix(A); 220 | for (int i = 0; i < k; ++i) { 221 | for (int j = i + 1; j < k; ++j) { 222 | addEdge(A, i, j); 223 | } 224 | } 225 | for (int i = k; i < n; ++i) { 226 | int u = i, v; 227 | for (int j = 0; j < k; ++j) { 228 | scanf("%d", &v); 229 | --v; 230 | addEdge(A, u, v); 231 | } 232 | } 233 | A.reshuffle(); 234 | int ans = solve(A); 235 | printf("%d\n", ans); 236 | return 0; 237 | } 238 | -------------------------------------------------------------------------------- /MatrixMultiplication_Test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | const int MOD = 1000000007, M = 52, LOG = 63; 9 | 10 | int m; // dimension 11 | 12 | struct Vector { 13 | int a[M]; 14 | 15 | Vector() { 16 | memset(a, 0, sizeof(a)); 17 | } 18 | 19 | int& operator[] (const int &i) { return a[i]; } 20 | const int operator[] (const int &i) const { return a[i]; } 21 | 22 | int operator * (const Vector &b) { 23 | int ret = 0; 24 | for (int i = 0; i < m; ++i) { 25 | if ((ret += (long long)a[i] * b[i] % MOD) >= MOD) { 26 | ret -= MOD; 27 | } 28 | } 29 | return ret; 30 | } 31 | 32 | Vector operator + (const Vector &b) { 33 | Vector ret; 34 | for (int i = 0; i < m; ++i) { 35 | if ((ret[i] = a[i] + b[i]) >= MOD) { 36 | ret[i] -= MOD; 37 | } 38 | } 39 | return ret; 40 | } 41 | 42 | }; 43 | 44 | Vector operator * (int k, const Vector &b) { 45 | Vector ret; 46 | for (int i = 0; i < m; ++i) { 47 | ret[i] = (long long)k * b[i] % MOD; 48 | } 49 | return ret; 50 | } 51 | 52 | // Reimplement this structure to support sparse matrix 53 | struct Matrix { 54 | int a[M][M]; 55 | 56 | int* operator[] (const int &i) { return a[i]; } 57 | const int* operator[] (const int &i) const { return a[i]; } 58 | 59 | Vector operator * (const Vector &b) { 60 | Vector ret; 61 | for (int i = 0; i < m; ++i) { 62 | for (int j = 0; j < m; ++j) { 63 | if ((ret[i] += (long long)a[i][j] * b[j] % MOD) >= MOD) { 64 | ret[i] -= MOD; 65 | } 66 | } 67 | } 68 | return ret; 69 | } 70 | }; 71 | 72 | // Berlekamp-Massey Algorithm 73 | 74 | int inverse(int a) { 75 | return a == 1 ? 1 : (long long)(MOD - MOD / a) * inverse(MOD % a) % MOD; 76 | } 77 | 78 | struct Poly { 79 | vector a; 80 | 81 | Poly() { a.clear(); } 82 | 83 | Poly(vector &a): a(a) {} 84 | 85 | int length() const { return a.size(); } 86 | 87 | Poly move(int d) { 88 | vector na(d, 0); 89 | na.insert(na.end(), a.begin(), a.end()); 90 | return Poly(na); 91 | } 92 | 93 | int calc(vector &d, int pos) { 94 | int ret = 0; 95 | for (int i = 0; i < (int)a.size(); ++i) { 96 | if ((ret += (long long)d[pos - i] * a[i] % MOD) >= MOD) { 97 | ret -= MOD; 98 | } 99 | } 100 | return ret; 101 | } 102 | 103 | Poly operator - (const Poly &b) { 104 | vector na(max(this->length(), b.length())); 105 | for (int i = 0; i < (int)na.size(); ++i) { 106 | int aa = i < this->length() ? this->a[i] : 0, 107 | bb = i < b.length() ? b.a[i] : 0; 108 | na[i] = (aa + MOD - bb) % MOD; 109 | } 110 | return Poly(na); 111 | } 112 | }; 113 | 114 | Poly operator * (const int &c, const Poly &p) { 115 | vector na(p.length()); 116 | for (int i = 0; i < (int)na.size(); ++i) { 117 | na[i] = (long long)c * p.a[i] % MOD; 118 | } 119 | return na; 120 | } 121 | 122 | vector Berlekamp(vector a) { 123 | int n = a.size(); 124 | Poly s, b; 125 | s.a.push_back(1), b.a.push_back(1); 126 | for (int i = 1, j = 0, ld = a[0]; i < n; ++i) { 127 | int d = s.calc(a, i); 128 | if (d) { 129 | if ((s.length() - 1) * 2 <= i) { 130 | Poly ob = b; 131 | b = s; 132 | s = s - (long long)d * inverse(ld) % MOD * ob.move(i - j); 133 | j = i; 134 | ld = d; 135 | } else { 136 | s = s - (long long)d * inverse(ld) % MOD * b.move(i - j); 137 | } 138 | } 139 | } 140 | return s.a; 141 | } 142 | 143 | // Calculating kth term of linear recurrence sequence 144 | // Modified for application 145 | 146 | struct LinearRec { 147 | 148 | int n; 149 | vector first; 150 | vector trans; 151 | vector > bin; 152 | 153 | vector add(vector &a, vector &b) { 154 | vector result(n * 2 + 1, 0); 155 | //You can apply constant optimization here to get a ~10x speedup 156 | for (int i = 0; i <= n; ++i) { 157 | for (int j = 0; j <= n; ++j) { 158 | if ((result[i + j] += (long long)a[i] * b[j] % MOD) >= MOD) { 159 | result[i + j] -= MOD; 160 | } 161 | } 162 | } 163 | for (int i = 2 * n; i > n; --i) { 164 | for (int j = 0; j < n; ++j) { 165 | if ((result[i - 1 - j] += (long long)result[i] * trans[j] % MOD) >= MOD) { 166 | result[i - 1 - j] -= MOD; 167 | } 168 | } 169 | result[i] = 0; 170 | } 171 | result.erase(result.begin() + n + 1, result.end()); 172 | return result; 173 | } 174 | 175 | LinearRec(vector &first, vector &trans):first(first), trans(trans) { 176 | n = first.size(); 177 | vector a(n + 1, 0); 178 | a[1] = 1; 179 | bin.push_back(a); 180 | for (int i = 1; i < LOG; ++i) { 181 | bin.push_back(add(bin[i - 1], bin[i - 1])); 182 | } 183 | } 184 | 185 | Vector calc(long long k) { 186 | vector a(n + 1, 0); 187 | a[0] = 1; 188 | for (int i = 0; i < LOG; ++i) { 189 | if (k >> i & 1) { 190 | a = add(a, bin[i]); 191 | } 192 | } 193 | Vector ret; 194 | for (int i = 0; i < n; ++i) { 195 | ret = ret + a[i + 1] * first[i]; 196 | } 197 | return ret; 198 | } 199 | }; 200 | 201 | Vector solve(Matrix &A, long long k, Vector &b) { 202 | vector vs; 203 | vs.push_back(A * b); 204 | for (int i = 1; i < m * 2; ++i) { 205 | vs.push_back(A * vs.back()); 206 | } 207 | if (k == 0) { 208 | return b; 209 | } else if (k <= m * 2) { 210 | return vs[k - 1]; 211 | } 212 | Vector x; 213 | for (int i = 0; i < m; ++i) { 214 | x[i] = rand() % MOD; 215 | } 216 | vector a(m * 2); 217 | for (int i = 0; i < m * 2; ++i) { 218 | a[i] = vs[i] * x; 219 | } 220 | vector s = Berlekamp(a); 221 | s.erase(s.begin()); 222 | for (int i = 0; i < s.size(); ++i) { 223 | s[i] = (MOD - s[i]) % MOD; 224 | } 225 | vector vf(vs.begin(), vs.begin() + s.size()); 226 | LinearRec f(vf, s); 227 | return f.calc(k); 228 | } 229 | 230 | //tested on CF 222E - Decoding Genome 231 | int n; 232 | 233 | long long k; 234 | 235 | int main() { 236 | scanf("%lld %d %d", &k, &m, &n); 237 | Matrix A; 238 | for (int i = 0; i < m; ++i) { 239 | for (int j = 0; j < m; ++j) { 240 | A[i][j] = 1; 241 | } 242 | } 243 | for (int i = 0; i < n; ++i) { 244 | char s[3]; 245 | scanf("%s", s); 246 | int t1 = 'a' <= s[0] && s[0] <= 'z' ? t1 = s[0] - 'a' : t1 = s[0] - 'A' + 26; 247 | int t2 = 'a' <= s[1] && s[1] <= 'z' ? t2 = s[1] - 'a' : t2 = s[1] - 'A' + 26; 248 | A[t1][t2] = 0; 249 | } 250 | Vector b; 251 | for (int i = 0; i < m; ++i) { 252 | b[i] = 1; 253 | } 254 | int ans = solve(A, k - 1, b) * b; 255 | printf("%d\n", ans); 256 | return 0; 257 | } 258 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Black Box Linear Algebra 2 | 3 | Code templates and slides for ICPCCamp 2017, Feb 13, Beijing. 4 | 5 | ## Files 6 | **`Black Box Linear Algebra.pdf` Slides (Chinese!)** 7 | 8 | **`LinearRecurrence.cpp` Template for calculating nth term of a linear recurrence sequence** 9 | 10 | `LinearRecurrence_Test1.cpp` Solving http://tdpc.contest.atcoder.jp/tasks/tdpc_fibonacci 11 | 12 | `LinearRecurrence_Test2.cpp` Solving http://abc009.contest.atcoder.jp/tasks/abc009_4 13 | 14 | **`Berlekamp-Massey.cpp` Template for Berlekamp-Massey Algorithm** 15 | 16 | `Berlekamp-Massey_Test.cpp` Template test 17 | 18 | **`MatrixMultiplication_Test.cpp` Application of previous two templates on http://codeforces.com/problemset/problem/222/E No constant optimization. Fastest by Feb 15, 2017 due to O(n^3), you might want to make a template out of this code** 19 | 20 | **`MatrixDeterminant_Test.cpp` Application of previous two templates on http://codeforces.com/contest/668/problem/F With some constant optimization. You might want a template version too** 21 | 22 | ## Bouns 23 | `How to AC it.pdf` Slides for ICPCCamp16 (Chinese) 24 | 25 | `Construction Problems.pdf` Slides for ICPCCamp15 (Chinese) 26 | 27 | === 28 | 29 | Authored by [Haobin Ni](https://github.com/FTRobbin), Jan-Feb 2017 30 | 31 | --------------------------------------------------------------------------------