【bzoj1009】[HNOI2008]GT考试(矩阵快速幂优化dp+kmp)
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1009
这道题一看数据范围:$ n<=10^9 $,显然不是数学题就是矩乘快速幂优化dp。
我们设$ f[i][j] $表示前$ i $位匹配不吉利数字$ j $位时的方案数,因为每一位的转移方式都是相同的,于是用kmp预处理出转移矩阵,直接矩乘快速幂就能过了。
#include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<ctime> #include<iostream> #include<algorithm> #include<queue> #include<vector> #include<map> #define ll long long #define ull unsigned long long #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) #define lowbit(x) (x& -x) #define inf 0x3f3f3f3f #define eps 1e-18 #define maxn 100010 inline ll read(){ll tmp=0; char c=getchar(),f=1; for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1; for(;'0'<=c&&c<='9';c=getchar())tmp=(tmp<<3)+(tmp<<1)+c-'0'; return tmp*f;} inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} inline void swap(int &a,int &b){int tmp=a; a=b; b=tmp;} using namespace std; struct matrix{ int size; int num[30][30]; }ans; int nxt[30]; char s[30]; int n,m,mod; matrix mul(matrix a,matrix b) { matrix c; memset(&c,0,sizeof(c)); c.size=a.size; for(int i=1;i<=a.size;i++) for(int j=1;j<=a.size;j++) for(int k=1;k<=a.size;k++) c.num[i][j]=(c.num[i][j]+a.num[i][k]*b.num[k][j])%mod; return c; } matrix power(matrix a,ll b) { matrix ans; memset(&ans,0,sizeof(ans)); ans.size=a.size; for(int i=1;i<=ans.size;i++)ans.num[i][i]=1; for(;b;b>>=1){ if(b&1)ans=mul(ans,a); a=mul(a,a); } return ans; } int main() { n=read(); m=read(); mod=read(); scanf("%s",s); nxt[1]=0; int tmp=0; for(int i=1;i<=m;i++){ while(tmp&&s[i]!=s[tmp])tmp=nxt[tmp]; if(s[i]==s[tmp])++tmp; nxt[i+1]=tmp; } for(int i=0;i<m;i++) for(int j='0';j<='9';j++){ int tmp=i; while(tmp&&j!=s[tmp])tmp=nxt[tmp]; if(j==s[tmp])++tmp; if(tmp<m)++ans.num[i+1][tmp+1]; } ans.size=m; ans=power(ans,n); int tot=0; for(int i=1;i<=m;i++) tot+=ans.num[1][i]; printf("%d\n",tot%mod); }