GDCPC2021 E - EXcellent Number(矩阵快速幂)

题目

source

题解

一眼看出是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;
	}
}
posted @ 2021-07-06 22:12  limil  阅读(175)  评论(0编辑  收藏  举报