[BZOJ1009][HNOI2008]GT考试
[BZOJ1009][HNOI2008]GT考试
试题描述
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0
他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0
输入
第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000
输出
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
输入示例
4 3 100 111
输出示例
81
数据规模及约定
见“输入”
题解
设计 dp,f(i, j) 表示考号前 i 位匹配到不吉利串第 j 位的方案数,考虑在 f(i, j) 这个状态下,在后面添加一位,那么有可能转到 f(i+1, j+1) 或 f(i+1, k),那么我们可以暴力求出这个 k,构造一下转移矩阵,快速幂一下就好了。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 25 int n, m, MOD; struct Matrix { int n, m, A[maxn][maxn]; Matrix() { n = m = 0; memset(A, 0, sizeof(A)); } Matrix operator * (const Matrix& t) const { Matrix ans; ans.n = t.n; ans.m = m; for(int i = 0; i <= ans.n; i++) for(int j = 0; j <= ans.m; j++) { ans.A[i][j] = 0; for(int k = 0; k <= n; k++) { ans.A[i][j] += (A[k][j] * t.A[i][k]) % MOD; if(ans.A[i][j] >= MOD) ans.A[i][j] -= MOD; } } return ans; } Matrix operator *= (const Matrix& t) { *this = *this * t; return *this; } } b, t; char S[maxn], tmp[maxn]; Matrix Pow(Matrix a, int b) { Matrix ans = a, t = a; b--; while(b) { if(b & 1) ans *= t; t *= t; b >>= 1; } return ans; } int main() { n = read(); m = read(); MOD = read(); scanf("%s", S + 1); for(int i = 1; i <= m; i++) S[i] -= '0'; for(int st = 0; st < m; st++) { int cnt = 0; for(int i = 1; i <= st; i++) tmp[++cnt] = S[i]; for(int x = 0; x <= 9; x++) { tmp[++cnt] = x; bool has = 0; for(int j = 1; j <= cnt; j++) { bool ok = 1; int k, i; for(k = j, i = 1; k <= cnt; k++, i++) if(tmp[k] != S[i]) { ok = 0; break; } if(ok) { has = 1; t.A[i-1][st]++; break; } } if(!has) t.A[0][st]++; cnt--; } } b.A[0][0] = 1; b.n = m; b.m = 0; t.n = t.m = m; // printf("\\ "); for(int i = 0; i <= t.n; i++) printf("%d ", i); putchar('\n'); // for(int i = 0; i <= t.n; i++) { // printf("%d ", i); // for(int j = 0; j <= t.m; j++) printf("%d ", t.A[i][j]); // putchar('\n'); // } b *= Pow(t, n); int ans = 0; for(int i = 0; i < m; i++) { ans += b.A[i][0]; if(ans >= MOD) ans -= MOD; } printf("%d\n", ans); return 0; }