1305. GT考试
1305. GT考試
題意:
準考證長度為n位,不吉利數字有m位,問不出現不吉利數字的準考證有多少種,答案mod K
題解:
動態規劃+kmp+矩陣快速冪
設dp[i][j]表示長度為i,且不包含S串,且末尾部分與S串的前綴匹配的最大長度是j的所有字符串的集合
S串為不吉利數字
現在相同部分為j,再黃色串后面再添加一個新數,有10種選擇0~9,
如果添加的正好等于紅色對應部分,那j++
如果不等于,就重新匹配最長部分,該如何快速匹配?用kmp的next數組,k=next[k],實現快速匹配最長長度
轉移方程:
dp[i+1][k]+=dp[i][k]
我們現在考慮兩層狀態之間的關系,即dp[i+1][…]與dp[i][…]的關系,我們可以列出這個式子
dp[i+1,0]=a00 * dp[i,0] +a01 * dp[i,1]…+
dp[i+1,1]=a10 * dp[i,0] + a11 * dp[i,1]+…+
而這些a可以組成一個矩陣A
由此可以得到:
dp[i+1] = dp[i] *A
所以dp[n] = f[n-1] *A =…=F[0] * An
F[0]表示長度為0的情況,F[0] = 1
A怎么得到?我們已經說過, dp[i+1][k]+=dp[i][k],也就是dp[i+1] = dp[i] *A,所以我們就把dp[i][k]加到對應的小a上即可,也就是動態規劃里的狀態我們加到A矩陣里,然后A求n-1次冪(矩陣快速冪)
代碼:
#include<bits/stdc++.h> #define debug(a,b) printf("%s = %d\n",a,b) typedef long long ll; using namespace std;inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w; } const int maxn=35; int n,m,mod; char str[maxn]; int ne[maxn]; int a[maxn][maxn]; void mul(int c[][maxn],int a[][maxn],int b[][maxn]) {static int t[maxn][maxn];memset(t,0,sizeof(t));for(int i=0;i<m;i++){for(int j=0;j<m;j++){for(int k=0;k<m;k++){t[i][j]=(t[i][j]+a[i][k]*b[k][j])%mod;}}}memcpy(c,t,sizeof(t)); } int qmi(int k) {int f0[maxn][maxn]={1};while(k){if(k&1)mul(f0,f0,a);//f0=f0*amul(a,a,a);//a=a*ak>>=1;}int res=0;for(int i=0;i<m;i++)res=(res+f0[0][i])%mod;return res; } int main() {cin>>n>>m>>mod;cin>>str+1;for(int i=2,j=0;i<=m;i++){while(j&&str[j+1]!=str[i])j=ne[j];if(str[j+1]==str[i])j++;ne[i]=j; }//初始化A矩陣 for(int j=0;j<m;j++){for(int c='0';c<='9';c++){int k=j;while(k&&str[k+1]!=c)k=ne[k];if(str[k+1]==c)k++;if(k<m)a[j][k]++;}}//F[n]=F[0]*A^ncout<<qmi(n)<<endl;return 0; }總結
以上是生活随笔為你收集整理的1305. GT考试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 耳鸣是肾虚的表现吗
- 下一篇: G - Tiling FZU - 204