GDCPC2021 E - EXcellent Number(矩陣快速冪)
阿新 • • 發佈:2021-07-06
題目
題解
一眼看出是kmp+數位dp,然後就掉坑裡了。。。
數位dp顯然時間會爆。觀察資料範圍,發現k長度最多為5,加上mod11的11個餘數,最多有55個狀態,可以使用矩陣快速冪。
假設\(f_{i,j}\)代表餘數為i,當前匹配位置為j的結果。任意寫出遞推式,直接套矩陣快速冪。初始只有\(f_{0,1}=1\)(匹配狀態從1開始),最終n次冪後將\(f_{i,len+1}\)和\(f_{0,i}\)全部加起來就是答案了。
#include<bits/stdc++.h> using namespace std; const int N = 500 + 10; const int M = 998244353; typedef long long ll; #define endl '\n' typedef long long ll; struct mat { ll arr[N][N]; int n; mat(const ll mx[N][N], int n) : n(n) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { arr[i][j] = mx[i][j]; } } } mat(int n) : n(n){ for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { arr[i][j] = 0; } } } mat(const mat& m) : mat(m.arr, m.n){} mat operator * (const mat &rhs) const { ll res[N][N]; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { ll sum = 0; for(int k = 1; k <= n; k++) { sum += arr[i][k] * rhs.arr[k][j] % M; sum %= M; } res[i][j] = sum; } } return mat(res, n); } }; int di[20]; int nt[20]; ll ans[N]; int len; void getnext() { int i = 1, j = 0; nt[i] = j; while(i <= len) { if(j == 0 || di[i] == di[j]) { i++; j++; nt[i] = j; } else { j = nt[j]; } } } int id(int st, int mod) { return mod * 7 + st; } mat qpow(mat A, int b) { mat res(100); for(int i = 1; i <= res.n; i++) res.arr[i][i] = 1; while(b) { if(b & 1) { res = res * A; } A = A * A; b = (b >> 1); } return res; } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int t; cin >> t; while(t--) { int n, k; cin >> n >> k; len = 0; bool flag = true; do{ if(k > 10 && (k % 10)) flag = false; else if(k < 10 && k != 1) flag = false; di[++len] = k % 10; k /= 10; } while(k); if(n + 1 < len) flag = false; getnext(); mat A(100); auto &arr = A.arr; for(int i = 1; i <= len + 1; i++) { for(int j = 0; j < 11; j++) { int id2 = id(i, j); for(int k = 0; k <= 9; k++) { int st = i, mod = j; if(st < len + 1) { while(st && k != di[st]) { st = nt[st]; } st++; } mod = (mod * 10 + k) % 11; int id1 = id(st, mod); arr[id1][id2]++; } } } mat res(qpow(A, n)); int tar = id(1, 0); for(int i = 1; i <= 100; i++) { ans[i] = res.arr[i][tar]; } ll tans = 0; for(int i = 0; i < 11; i++) { tans += ans[id(len + 1, i)]; tans %= M; } for(int i = 1; i <= len; i++ ) { tans += ans[id(i, 0)]; tans %= M; } cout << (tans + flag) % M << endl; } }