#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 }
时间: 2024-10-06 02:18:58