小明認為只有數字4和7是幸運數字,其他數字都不是。
如果一個整數的每個數字都是幸運數字,那麼該整數就是幸運整數。
給出一個陣列numbers[1...n]。
一個長度為L的幸運數列A[0],A[1],A[2],...A[L-1]必須同時滿足:
1、對於0<=i<L, A[i]必須是幸運整數。
2、對於0<=i<L-1,A[i]的最後一個數字必須等於A[i+1]的第一個數字。
3、 對於0<=i<L, 至少存在一個下標j滿足A[i] = numbers[j]。
輸出有多少個不同的長度為L的幸運序列,答案模1234567891。
提示:對於兩個長度都是L的幸運序列A[0], A[1], ..., A[L- 1] 和 B[0], B[1], ..., B[L - 1],他們被認為是不同序列的條件是:存在一個下標i, 使得A[i] != B[i]
輸入格式
第一行,兩個整數,n和L。 1<=n<=50, 1<=L<=1e9。
第二行,n個整數,第i個整數是numbers[i], 1<=numbers[i]<=1e9。
輸出格式
一個整數
輸入/輸出例子1
輸入:
3 3
47 74 47
輸出:
2
輸入/輸出例子2
輸入:
5 47
100 4774 200 747 300
輸出:
2
樣例解釋
無
首先,根據題意,我們先初始化,後面方便d
1.篩除不含4,7的數
2.去重
3.分類-4類
1) 4開頭4結尾
2) 4開頭7結尾
3) 7開頭4結尾
4) 7開頭7結尾
然後就很容易定出dp了
f(i, j): 當前已經構造的長度是i,並且第i個數是第j類
假設
cnt1表示 有多少個第一類
cnt2表示有多少個第二類
cnt3,cnt4以此類推
那麼可以推出轉移方程
f(L, 1)=( f(L-1, 1)+f(L-1, 3) ) * cnt1
f(L, 2)=( f(L-1, 1)+f(L-1, 3) ) * cnt2
f(L, 3)=( f(L-1, 2)+f(L-1, 4) ) * cnt3
f(L, 4)=( f(L-1, 2)+f(L-1, 4) ) * cnt4
舉個例:
f(L, 3)表示長度為L,第L個數是第3類的(7開頭,4結尾)
那麼 L 肯定由 L-1 轉移轉移過來的。由於第L個數是7開頭的,那麼L-1個數肯定是7結尾的,然後我們考慮第L這一位,它可以從7開頭7結尾的數中任選一個,也就是要乘上cnt3
剩餘的同上。
推完dp後,可以開始矩陣加速了
由於平常的矩陣都是一維的,這裡卻是二維,不好算
我們考慮降維,我們把第一維拆分成階段,(矩陣不斷遞推,不就算作為階段麼)第二維成為矩陣中的內容
[f1, f2, f3, f4]
假設當前已構造的長度是L
f1:長度是L的第1類的方案數
f2:長度是L的第2類的方案數
f3:長度是L的第3類的方案數
f4:長度是L的第4類的方案數
目標矩陣長度就是L+1
[f1', f2', f3', f4']
f1':長度是L+1的第1類的方案數
......
f1' = cnt1*f1+ cnt1*f3
f2' = cnt2*f1+ cnt2*f3
......(跟dp一個樣,沒啥好補充的了)
[f1, f2, f3, f4] * [B] = [f1', f2', f3', f4']
[B]:(根據上面的式子即可求出)
[cnt1, cnt2, 0, 0 ]
[0, 0, cnt3, cnt4 ]
[cnt1, cnt2, 0, 0]
[0, 0, cnt3, cnt4]
答案:
[f1, f2, f3, f4]*[B]^(L-1)
ans=f1+f2+f3+f4
#include <bits/stdc++.h> #define int long long using namespace std; const int N=55, Mod=1234567891; struct mp { int n, m; int a[N][N]; void init(int row, int col, bool isI) { n=row, m=col; memset(a, 0, sizeof a); if (isI) for (int i=1; i<=row; i++) a[i][i]=1; } }A, B; mp operator * (const mp A, const mp B) { mp C; C.init(A.n, B.m, 0); for (int i=1; i<=A.n; i++) for (int j=1; j<=B.m; j++) for (int k=1; k<=A.m; k++) C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%Mod; return C; } mp qpow_mp(mp A, int k) { mp res; res.init(A.n, A.m, 1); while (k>0) { if (k&1) res=res*A; A=A*A; k>>=1; } return res; } int n, m, L, x, a[N], cnt[N]; signed main() { scanf("%lld%lld", &n, &L); for (int i=1; i<=n; i++) { int t=0; bool ok=1; scanf("%lld", &x); t=x; while (t>0) { if (t%10!=4 && t%10!=7) { ok=0; break; } t/=10; } if (ok) a[++m]=x; } // printf("{%d}", m); sort(a+1, a+1+m); m=unique(a+1, a+1+m)-a-1; // printf("{%d}", m); for (int i=1; i<=m; i++) { int t=a[i], fst=0, lst=0; while (t>0) { if (fst==0) fst=t%10; lst=t%10; t/=10; } if (fst==4 && lst==4) cnt[1]++; if (fst==4 && lst==7) cnt[2]++; if (fst==7 && lst==4) cnt[3]++; if (fst==7 && lst==7) cnt[4]++; } A.init(1, 4, 0); A.a[1][1]=cnt[1], A.a[1][2]=cnt[2], A.a[1][3]=cnt[3], A.a[1][4]=cnt[4]; B.init(4, 4, 0); B.a[1][1]=cnt[1], B.a[1][2]=cnt[2], B.a[1][3]=0, B.a[1][4]=0; B.a[2][1]=0, B.a[2][2]=0, B.a[2][3]=cnt[3], B.a[2][4]=cnt[4]; B.a[3][1]=cnt[1], B.a[3][2]=cnt[2], B.a[3][3]=0, B.a[3][4]=0; B.a[4][1]=0, B.a[4][2]=0, B.a[4][3]=cnt[3], B.a[4][4]=cnt[4]; A=A*qpow_mp(B, L-1); printf("%lld", (((A.a[1][1]+A.a[1][2])%Mod+A.a[1][3])%Mod+A.a[1][4])%Mod); return 0; }