LOJ2325. 「清华集训 2017」小 Y 和恐怖的奴隶主【矩阵快速幂优化DP】【倍增优化】

LINK


思路

首先是考虑怎么设计dp的状态
发现奴隶主的顺序没有影响,只有生命和个数有影响,所以就可以把每个生命值的奴隶主有多少压缩成状态就可以了
然后发现无论是什么时候一个状态到另一个状态的转移都是固定的方式
所以可以预处理转移矩阵用矩阵快速幂进行优化

但是如果在计算的时候暴力(状态^3)进行转移会TLE
但是注意到在这个时候有用的状态其实只有一个向量
所以就预处理倍增然后用向量乘矩阵来优化到单次(logn状态^2)就可以了

有点卡常


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) x = (x<<1) + (x<<3) + c -'0', c = getchar();
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) putchar('-'), x = -x;
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 170;
const int Mod = 998244353;
ll n, m, K, cnt = 0;
int inv[10];
int id[9][9][9];
struct Matrix{
  int t[N][N];
  Matrix() { memset(t, 0, sizeof(t));}
}trans, g[61];
inline int add(int a, int b) { return ((a += b) > Mod) ? (a - Mod) : a; }
inline int mul(int a, int b) { return 1ll * a * b % Mod; }
Matrix operator * (const Matrix a, const Matrix b) {
  Matrix c;
  fu(k, 0, cnt)
    fu(i, 0, cnt) if (a.t[i][k])
      fu(j, 0, cnt)
        c.t[i][j] = add(c.t[i][j], mul(a.t[i][k], b.t[k][j]));
  return c;
}
inline Matrix mul_matrix(Matrix a, Matrix b) {
  Matrix c;
  fu(k, 0, cnt) if(a.t[0][k])
    fu(j, 0, cnt) 
      c.t[0][j] = add(c.t[0][j], mul(a.t[0][k], b.t[k][j]));
  return c;
}
inline int fast_pow(int a, int b) {
  int ans = 1;
  while (b) {
    if (b & 1) ans = mul(ans, a);
    b >>= 1;
    a = mul(a, a);
  }
  return ans;
}
inline int get_add_id(int i, int j, int k) {
  if (i + j + k == K) return id[i][j][k];
  if (m == 1) return id[i + 1][j][k];
  if (m == 2) return id[i][j + 1][k];
  if (m == 3) return id[i][j][k + 1];
}
void init() {
  fu(i, 1, K + 1)inv[i] = fast_pow(i, Mod - 2);
  int upj, upk, ID, inv_sum;
  fu(i, 0, K) {
    upj = (m == 1)? 0 : K - i;
    fu(j, 0, upj) {
      upk = (m == 2)? 0 : K - i - j; 
      fu(k, 0, upk) id[i][j][k] = ++cnt;
    }
  }
  ++cnt;
  trans.t[cnt][cnt] = 1;
  fu(i, 0, K) {
    upj = (m == 1)? 0 : K - i;
    fu(j, 0, upj) {
      upk = (m == 2)? 0 : K - i - j; 
      fu(k, 0, upk) {
        ID = id[i][j][k], inv_sum = inv[i + j + k + 1];
        if (i) trans.t[ID][id[i - 1][j][k]] = mul(inv_sum, i);
        if (j) trans.t[ID][get_add_id(i + 1, j - 1, k)] = mul(inv_sum, j);
        if (k) trans.t[ID][get_add_id(i, j + 1, k - 1)] = mul(inv_sum, k);    
        trans.t[ID][ID] = trans.t[ID][cnt] = inv_sum;
      }
    }
  }
  g[0] = trans;
  fu(i, 1, 60) g[i] = g[i - 1] * g[i - 1];
}
int main() {
#ifdef dream_maker
  freopen("input.txt","r",stdin);
#endif
  int T;Read(T);
  Read(m); Read(K);
  init();
  int pre = get_add_id(0, 0, 0);
  while (T--) {
    Read(n);
    Matrix ans;
    ans.t[0][pre] = 1;
    fu(i, 0, 60)
      if ((n >> i) & 1) ans = mul_matrix(ans, g[i]);
    printf("%d
", ans.t[0][cnt]);
  }
  return 0;
}
原文地址:https://www.cnblogs.com/dream-maker-yk/p/9735969.html