#1560 : H国的身份证号码II(dp+矩阵快速幂)

#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

 

posted @ 2017-08-21 11:04  happy_codes  阅读(336)  评论(0编辑  收藏  举报