1. 程式人生 > >#1560 : H國的身份證號碼II(dp+矩陣快速冪)

#1560 : H國的身份證號碼II(dp+矩陣快速冪)

font str code size logs set esp 發現 由於

#1560 : H國的身份證號碼II

時間限制:10000ms 單點時限:1000ms 內存限制:256MB

描述

H國的身份證號碼是一個N位的正整數(首位不能是0)。此外,由於防偽需要,一個N位正整數是合法的身份證號碼當且僅當每位數字都小於等於K,並且任意相鄰兩位數字的乘積也小於等於K。

例如對於K=5, 101、211、210等都是合法的號碼,而106、123、421等都是非法的號碼。

給定一個正整數N以及K,H國總統想知道一共有多少個合法的號碼可用。

輸入

兩個整數N和K。

對於30%的數據,1 ≤ N ≤ 10

對於50%的數據,1 ≤ N ≤ 1000000

對於100%的數據,1 ≤ N ≤ 1012,1 ≤ K ≤ 81。

輸出

合法號碼的總數。由於答案可能非常大,你只需要輸出答案對109+7取模的結果。

樣例輸入

2 4

樣例輸出

12

//dp[i][j] 代表 i 長度,結尾為 j 的合法方案數

那麽容易想到

i = 1 : dp[1][j] = 1 (j<=k)

i > 1 : dp[i][j] = ∑dp[i-1][x] (x<=k&&j<=k&&j*x<=k) 可以發現,可以用矩陣快速冪優化,O(103*logn)
技術分享
  1 # include <cstdio>
  2 # include <cstring>
  3 # include <cstdlib>
  4 # include <iostream>
  5 # include <vector>
  6 # include <queue>
  7 # include <stack>
  8 # include <map>
  9 # include <bitset>
 10 # include <sstream>
 11
# include <set> 12 # include <cmath> 13 # include <algorithm> 14 # pragma comment(linker,"/STACK:102400000,102400000") 15 using namespace std; 16 # define LL long long 17 # define pr pair 18 # define mkp make_pair 19 # define lowbit(x) ((x)&(-x)) 20 # define PI acos(-1.0) 21 # define INF 0x3f3f3f3f3f3f3f3f 22 # define eps 1e-8 23 # define MOD 1000000007 24 25 inline int scan() { 26 int x=0,f=1; char ch=getchar(); 27 while(ch<0||ch>9){if(ch==-) f=-1; ch=getchar();} 28 while(ch>=0&&ch<=9){x=x*10+ch-0; ch=getchar();} 29 return x*f; 30 } 31 inline void Out(int a) { 32 if(a<0) {putchar(-); a=-a;} 33 if(a>=10) Out(a/10); 34 putchar(a%10+0); 35 } 36 #define MX 10 37 /**************************/ 38 struct Mat 39 { 40 LL m[MX][MX]; 41 }unit,di,fir; 42 43 LL n,k; 44 45 Mat mult(Mat a,Mat b) 46 { 47 Mat c; 48 for (int i=0;i<MX;i++) 49 for (int j=0;j<MX;j++) 50 { 51 c.m[i][j]=0; 52 for (int k=0;k<MX;k++) 53 c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%MOD; 54 } 55 return c; 56 } 57 58 Mat cal(LL p) 59 { 60 Mat ret = unit, b = di; 61 while (p) 62 { 63 if (p&1) ret = mult(ret,b); 64 b = mult(b,b); 65 p/=2; 66 } 67 return ret; 68 } 69 70 void Init() 71 { 72 for (int i=0;i<MX;i++) 73 unit.m[i][i]=1; 74 for (int i=1;i<MX;i++) 75 { 76 if (i<=k) 77 fir.m[i][0]=1; 78 } 79 for (int i=0;i<MX;i++) 80 { 81 for (int j=0;j<MX;j++) 82 { 83 if (i<=k&&j<=k&&i*j<=k) 84 di.m[i][j]=di.m[j][i]=1; 85 } 86 } 87 } 88 89 int main() 90 { 91 scanf("%lld%lld",&n,&k); 92 Init(); 93 Mat sa = fir; 94 Mat sb = cal(n-1); 95 sb = mult(sb,sa); 96 97 LL ans = 0; 98 for (int i=0;i<MX;i++) 99 { 100 ans = (ans + sb.m[i][0])%MOD; 101 } 102 printf("%lld\n",ans); 103 return 0; 104 }
View Code

#1560 : H國的身份證號碼II(dp+矩陣快速冪)