跳转至

20220327-线性代数

0.5h 矩阵乘法 [TJOI2017]可乐 图上路径数 提高 https://www.luogu.com.cn/problem/P3758
1h 矩阵乘法 Recurrences,UVa10870 伴随矩阵 提高+ https://www.luogu.com.cn/problem/UVA10870
1h 矩阵乘法 USACO2007 Nov G. Cow Relays Floyd 加速 提高+ https://www.luogu.com.cn/problem/P2886
1h 矩阵乘法 [2020-NOI Online #3 提高组] 魔法值 DP 加速 提高+ https://www.luogu.com.cn/problem/P6569
0.5h 矩阵乘法 CF691E Xor-sequences DP 加速 提高 https://codeforces.com/contest/691/problem/E
0.5h 高斯消元 [JSOI2008]球形空间产生器 方程转换 提高+ https://www.luogu.com.cn/problem/P4035
0.5h 矩阵乘法 [TJOI2019]甲苯先生的字符串 路径统计 提高+ https://www.luogu.com.cn/problem/P5337
0.75h 高斯消元 乘积是平方数(Square, UVa11542) 异或方程 NOI- https://www.luogu.com.cn/problem/UVA11542
2h 矩阵线段树 CF718C. Sasha and Array 斐波那契 NOI- https://codeforces.com/problemset/problem/718/C
1h 矩阵乘法 Balkan OI 2009 - Reading 分层图 NOI- https://www.luogu.com.cn/problem/P6841
0.25h 高斯消元 [JSOI2008]球形空间产生器 方程转换 提高+ https://www.luogu.com.cn/problem/P4035
1h 高斯消元 [SDOI2010] 外星千足虫 异或方程 提高+ https://www.luogu.com.cn/problem/P2447
1h 矩阵乘法 Recurrences,UVa10870 伴随矩阵 提高+ https://www.luogu.com.cn/problem/UVA10870

可乐

#include <bits/stdc++.h>
using namespace std;
const int MOD = 2017;
typedef long long ll;
typedef vector<int> vi;
struct Mat {
  int r, c;
  vector<vi> f;
  Mat(int _r, int _c) : r(_r), c(_c), f(r + 1, vi(c + 1)) {}
  Mat operator*(const Mat &b) const {
    Mat m(r, b.c);
    for (int i = 1; i <= m.r; ++i)
      for (int j = 1; j <= m.c; ++j)
        for (int k = 1; k <= m.c; ++k)
          (m.f[i][j] += f[i][k] * b.f[k][j] % MOD) %= MOD;
    return m;
  }
  Mat operator^(ll x) const {
    assert(r == c);
    Mat m = *this, p = *this;
    for (--x; x; x >>= 1, p = p * p)
      if (x & 1) m = m * p;
    return m;
  }
};
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n, m, t;
  cin >> n >> m;
  ++n;
  Mat G(n, n), A(1, n);
  for (int u, v, i = 1; i <= m; ++i) cin >> u >> v, G.f[u][v] = G.f[v][u] = 1;

  for (int i = 1; i <= n; ++i) G.f[i][i] = 1;
  for (int i = 1; i < n; ++i) G.f[i][n] = 1;
  cin >> t;
  A.f[1][1] = 1, A = A * (G ^ t);
  int ans = 0;
  for (int i = 1; i <= n; ++i) (ans += A.f[1][i]) %= MOD;
  cout << ans << endl;
  return 0;
}

Recurrences(未完成)

Cow Relays

很容易想到 N 次矩阵乘法的思路,不同的是这次的是长度而不是方案数(所以是加法而不是乘法)、是最小值而不是总数,所以把*换成+,把+换成min

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = (a); i < (int)b; ++i)
const int MV = 205, INF = 0x7f7f7f7f;
typedef int Mat[MV][MV];
int sz;
void matmul(Mat A, Mat B, Mat C) {
  static Mat m;
  memset(m, 0x7f, sizeof(Mat));
  rep(i, 0, sz) rep(j, 0, sz) rep(k, 0, sz) {
    if (A[i][k] != INF && B[k][j] != INF)
      m[i][j] = min(m[i][j], A[i][k] + B[k][j]);
  }
  memcpy(C, m, sizeof(Mat));
}
void matpow(Mat A, int n, Mat r) {
  Mat a;
  memcpy(a, A, sizeof(a));
  memcpy(r, A, sizeof(Mat));
  --n;
  for (int i = 0; (1 << i) <= n; ++i) {
    if (n & (1 << i)) matmul(r, a, r);
    matmul(a, a, a);
  }
}
map<int, int> ID;
int getId(int u) {
  if (!ID.count(u)) ID[u] = sz++;
  return ID[u];
}
Mat G, Ans;
int main() {
  int N, T, S, E;
  cin >> N >> T >> S >> E;
  sz = 0, memset(G, 0x7f, sizeof(G));
  for (int i = 1, u, v, w; i <= T; ++i) {
    cin >> w >> u >> v;
    u = getId(u), v = getId(v);
    G[u][v] = G[v][u] = min(G[u][v], w);
  }
  matpow(G, N, Ans);
  cout << Ans[getId(S)][getId(E)] << endl;
}

魔法值

#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a); i < (b); ++i)
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
struct Mat {
  int r, c;
  vector<vl> f;
  Mat(int r, int c) : r(r), c(c), f(r, vl(c)) {}
  Mat operator*(const Mat &b) {
    Mat m(r, b.c);
    rep(i, 0, m.r) rep(j, 0, m.c) rep(k, 0, c) m.f[i][j] ^= f[i][k] * b.f[k][j];
    return m;
  }
};
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  const int BT = 32;
  int n, m, q;
  cin >> n >> m >> q;
  Mat f0(1, n);
  vector<Mat> E(BT, Mat(n, n));
  rep(i, 0, n) cin >> f0.f[0][i];
  for (int i = 0, u, v; i < m; ++i) {
    cin >> u >> v;
    --u, --v;
    E[0].f[u][v] = E[0].f[v][u] = 1;
  }
  rep(i, 1, BT) E[i] = E[i - 1] * E[i - 1];
  Mat f(1, n);
  for (ll a = 0; q; --q) {
    Mat f = f0;
    cin >> a;
    for (int i = 0; (1LL << i) <= a; ++i) {
      if (a & (1LL << i)) f = f * E[i];
    }
    cout << f.f[0][0] << endl;
  }
}

球形空间产生器

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
// b: 系数矩阵,c: 常数
double a[20][20], b[20], c[20][20];
int n;
int main() {
  cin >> n;
  for (int i = 1; i <= n + 1; ++i)
    for (int j = 1; j <= n; ++j) scanf("%lf", &a[i][j]);
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j) {
      c[i][j] = 2 * (a[i][j] - a[i + 1][j]);
      b[i] += a[i][j] * a[i][j] - a[i + 1][j] * a[i + 1][j];
    }
  // 高斯消元
  for (int i = 1; i <= n; ++i) {
    // 找到 x[i] 的系数不为 0 的一个方程
    for (int j = i; j <= n; ++j) {
      if (fabs(c[j][i]) > eps) {
        for (int k = 1; k <= n; ++k) swap(c[i][k], c[j][k]);
        swap(b[i], b[j]);
      }
    }
    // 消去其它方程 x[i] 的系数
    for (int j = 1; j <= n; ++j) {
      if (i == j) continue;
      double rate = c[j][i] / c[i][i];
      for (int k = i; k <= n; ++k) c[j][k] -= c[i][k] * rate;
      b[j] -= b[i] * rate;
    }
  }
  for (int i = 1; i <= n; ++i) printf("%.3f ", b[i] / c[i][i]);
  printf("\n");
}

甲苯先生的字符串

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7, SG = 26;
typedef long long ll;
#define rep(i, a, b) for (int i = (a); i < (b); ++i)

struct Mat {
  ll f[SG][SG];
  Mat() { memset(f, 0, sizeof(f)); }
  Mat operator*(const Mat &b) const {
    Mat m;
    rep(i, 0, SG) rep(j, 0, SG) rep(k, 0, SG) {
      (m.f[i][j] += f[i][k] * b.f[k][j] % MOD) %= MOD;
    }
    return m;
  }
};
Mat matpow(Mat a, ll b) {
  Mat m;
  rep(i, 0, SG) m.f[i][i] = 1;
  for (; b; a = a * a, b >>= 1) {
    if (b & 1) m = m * a;
  }
  return m;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  Mat G, A, SumG;
  rep(i, 0, SG) {
    A.f[0][i] = SumG.f[i][0] = 1;
    rep(j, 0, SG) G.f[i][j] = 1;
  }
  ll n;
  string s;
  cin >> n >> s;
  rep(i, 1, s.size()) G.f[s[i - 1] - 'a'][s[i] - 'a'] = 0;
  cout << (A * matpow(G, n - 1) * SumG).f[0][0] << endl;
}

Square

#include <bits/stdc++.h>
using namespace std;
const int maxn = 110, maxp = 510;
int vis[maxn], prime[maxp];
int get_primes(int n) {
  int m = (int)sqrt(n + 0.5);
  memset(vis, 0, sizeof(vis));
  for (int i = 2; i <= m; ++i)
    if (!vis[i])
      for (int j = i * i; j <= n; j += i) vis[j] = 1;
  int c = 0;
  for (int i = 2; i <= n; ++i)
    if (!vis[i]) prime[c++] = i;
  return c;
}
typedef int Mat[maxn][maxn];
int rank_(Mat A, int m, int n) {
  int i = 0, j = 0, k, r, u;
  while (i < m && j < n) {
    r = i;
    for (k = i; k < m; ++k)
      if (A[k][j]) {
        r = k;
        break;
      }
    if (A[r][j]) {
      if (r != i)
        for (k = 0; k <= n; ++k) swap(A[r][k], A[i][k]);
      for (int u = i + 1; u < m; ++u)
        if (A[u][j])
          for (k = i; k <= n; ++k) A[u][k] ^= A[i][k];
      i++;
    }
    j++;
  }
  return i;
}
Mat A;
int main() {
  int m = get_primes(500);
  int T;
  cin >> T;
  while (T--) {
    int n, maxp = 0;
    long long x;
    cin >> n;
    memset(A, 0, sizeof(A));
    for (int i = 0; i < n; ++i) {
      cin >> x;
      for (int j = 0; j < m; ++j)
        while (x % prime[j] == 0) {
          maxp = max(maxp, j);
          x /= prime[j];
          A[j][i] ^= 1;
        }
    }
    int r = rank_(A, maxp + 1, n);
    cout << (1LL << (n - r)) - 1 << endl;
  }
}

Sasha and Array(未完成)

Reading

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b) for (int i = (a); i < (int)(b); ++i)
const int MOD = 1e9 + 7, SIG = 26, FF = 5, SZ = SIG * FF + 1;
typedef vector<ll> vl;
struct Mat {
  int r, c;
  vector<vl> f;
  Mat(int r, int c) : r(r), c(c), f(r, vl(c)){};
  Mat operator*(const Mat& b) const {
    Mat m(r, b.c);
    rep(i, 0, m.r) rep(j, 0, m.c) rep(k, 0, m.c) {
      (m.f[i][j] += f[i][k] * b.f[k][j] % MOD) %= MOD;
    }
    return m;
  }
  Mat pow(ll b) const {
    Mat m = *this, p = *this;
    for (--b; b; p = p * p, b >>= 1) {
      if (b & 1) m = m * p;
    }
    return m;
  }
};
int main() {
  Mat G(SZ, SZ);
  rep(i, 0, SIG) {
    rep(j, 0, SIG) G.f[i * FF][j * FF] = 1;
    rep(f, 0, FF - 1) G.f[i * FF + f + 1][i * FF + f] = 1;
  }
  int s = SIG;
  rep(i, 0, SIG) G.f[s * FF][i * FF] = 1;
  G.f[s * FF][s * FF] = 1;
  int n, m, ans = 0;
  cin >> n >> m;
  for (int i = 0, f; i < m; ++i) {
    char a, b;
    cin >> a >> b >> f;
    int i1 = (a - 'a') * FF, i2 = (b - 'a') * FF;
    G.f[i1][i2] = 0, G.f[i1][i2 + f - 1] = 1;
    G.f[i2][i1] = 0, G.f[i2][i1 + f - 1] = 1;
  }
  G = G.pow(n + 1);
  rep(i, 0, SIG)(ans += G.f[SIG * FF][i * FF]) %= MOD;
  cout << ans << endl;
}

球形空间产生器

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
// b: 系数矩阵,c: 常数
double a[20][20], b[20], c[20][20];
int n;
int main() {
  cin >> n;
  for (int i = 1; i <= n + 1; ++i)
    for (int j = 1; j <= n; ++j) scanf("%lf", &a[i][j]);
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j) {
      c[i][j] = 2 * (a[i][j] - a[i + 1][j]);
      b[i] += a[i][j] * a[i][j] - a[i + 1][j] * a[i + 1][j];
    }
  // 高斯消元
  for (int i = 1; i <= n; ++i) {
    // 找到 x[i] 的系数不为 0 的一个方程
    for (int j = i; j <= n; ++j) {
      if (fabs(c[j][i]) > eps) {
        for (int k = 1; k <= n; ++k) swap(c[i][k], c[j][k]);
        swap(b[i], b[j]);
      }
    }
    // 消去其它方程 x[i] 的系数
    for (int j = 1; j <= n; ++j) {
      if (i == j) continue;
      double rate = c[j][i] / c[i][i];
      for (int k = i; k <= n; ++k) c[j][k] -= c[i][k] * rate;
      b[j] -= b[i] * rate;
    }
  }
  for (int i = 1; i <= n; ++i) printf("%.3f ", b[i] / c[i][i]);
  printf("\n");
}

外星千足虫

#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a); i <= (int)(b); ++i)

using namespace std;
const int N = 1004;
bitset<N> Mat[2 * N];
int gauss(int n, int m) {
  int k = -1;
  rep(i, 1, n) {
    int cur = i;
    while (cur <= m && !Mat[cur][i]) cur++;
    if (cur > m) return 0;
    k = max(k, cur);
    if (cur != i) swap(Mat[cur], Mat[i]);
    rep(j, 1, m) if (i != j && Mat[j].test(i)) Mat[j] ^= Mat[i];
  }
  return k;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int n, m;
  cin >> n >> m;
  string s;
  for (int i = 1, b; i <= m; ++i) {
    cin >> s >> b;
    rep(j, 1, n) Mat[i].set(j, s[j - 1] == '1');
    Mat[i].set(0, b);
  }
  int k = gauss(n, m);
  if (k) {
    cout << k << endl;
    rep(i, 1, n) cout << (Mat[i][0] ? "?y7M#" : "Earth") << endl;

  } else {
    cout << "Cannot Determine\n";
  }
}