1. 程式人生 > >[ACM-ICPC 2018 焦作賽區網路預賽][L.Poor God Water][AC自動機(偽)+矩陣快速冪]

[ACM-ICPC 2018 焦作賽區網路預賽][L.Poor God Water][AC自動機(偽)+矩陣快速冪]

題意

T組資料,構造長度為N的串,不含111,222,333,132,231,313,323字串的方案數

資料範圍:T \leq 1000, 1 \leq N \leq 10^{10}

分析

AC自動機構造矩陣,但我不會(目前)_(°:з」∠)_

可以將合法的三元串xyz看作xy->yz,這就形成了一個轉移關係那麼11->11就是非法的,13->32也是非法的

這就可以填充一個9*9的矩陣A,A^n中元素a_n[i][j]表示從i轉移到j的合法種數,A^n所有元素和即為答案。

PS:比賽時丟臉的用trie樹手寫了一個29*29的矩陣(把用111->11,21->213這種來表示轉移),線上丟臉ε=ε=ε=ε=ε=ε=┌(; ̄◇ ̄)┘

#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
using namespace std;

using LL = long long;
const int MOD = 1e9 + 7;
struct matrix {
  LL num[55][55], len;
  void init(){
    memset(num, 0, sizeof(num));
    len = 0;
  }
  matrix operator *(const matrix &a){
    matrix res;
    res.init(), res.len = a.len;
    for(int i = 0; i < len; i++)
      for(int j = 0; j < len; j++)
        for(int k = 0; k < len; k++)
          res.num[i][j] += (num[i][k] * a.num[k][j]) % MOD, res.num[i][j] %= MOD;
    return res;
  }
  void getprint(){
    for(int i = 0; i < len; i++){
      for(int j = 0; j < len; j++)
        printf("%3lld ", num[i][j]);
      printf("\n");
    }
  }
} A;
matrix qpow_matraix(matrix x, LL n);
LL T, N;

int main(){
  A.init(), A.len = 9;
  int i, j;
  for(i = 0; i < 9; i++)
    for(j = 0; j < 3; j++) A.num[i][j + i % 3 * 3] = 1;
  A.num[0][0] = 0;//11->11
  A.num[2][7] = 0;//13->32
  A.num[4][4] = 0;//22->22
  A.num[5][6] = 0;//23->31
  A.num[6][2] = 0;//31->13
  A.num[7][5] = 0;//32->23
  A.num[8][8] = 0;//33->33
  //A.getprint();
  cin >> T;
  while(T--){
    cin >> N;
    if(N == 1){cout << 3 << endl; continue;}
    else if(N == 2){cout << 9 << endl; continue;}
    LL ans = 0;
    matrix tmp = qpow_matraix(A, N - 2);
    for(i = 0; i < tmp.len; i++)
      for(j = 0; j < tmp.len; j++) ans += tmp.num[i][j], ans %= MOD;
    cout << ans << endl;
  }
  return 0;
}

matrix qpow_matraix(matrix X, LL n){
  matrix E;
  E.init(), E.len = X.len;
  int i;
  for(i = 0; i <= E.len; i++) E.num[i][i] = 1;
  while(n){
    if(n & 1) E = E * X;
    X = X * X;
    n >>= 1;
  }
  return E;
}