1. 程式人生 > >BZOJ3679: 數字之積 數位DP

BZOJ3679: 數字之積 數位DP

Description
一個數x各個數位上的數之積記為f(x) <不含前導零>
求[L,R)中滿足0 < f(x) <= n的數的個數

Sample Input
5
19 22

Sample Output
1

突然發現自己沒寫過數位DP的blog,寫一篇!!!
首先我們發現直接開陣列n太大會爆炸。。。
然後我們發現其實1~9的質因數是有限的:2、3、5、7
那你開一個五維陣列f[i][x2][x3][x5][x7]表示到第i位,有x2個2,x3個3,x5個5,x7個7。
然後就數位DP亂搞。。。

#include <cstdio>
#include <cstring> using namespace std; typedef long long LL; LL f[20][31][21][13][12]; int n, a[20], len; int k2, k3, k5, k7; LL dfs(int x, int x2, int x3, int x5, int x7, bool pd, bool limit) { LL oo = 1; for(int i = 1; i <= x2; i++) oo *= 2; for(int i = 1; i <= x3; i++) oo *= 3
; for(int i = 1; i <= x5; i++) oo *= 5; for(int i = 1; i <= x7; i++) oo *= 7; if(oo > n) return 0; if(x == 0) { if(oo <= n && !pd) return 1; else return 0; } if(f[x][x2][x3][x5][x7] != -1 && !limit && !pd) return f[x][x2][x3][x5][x7]; int
up = 9; LL ans = 0; if(limit) up = a[x]; if(pd) ans += dfs(x - 1, x2, x3, x5, x7, 1, limit); for(int i = 1; i <= up; i++) { bool uu = 0; if(limit == 1 && i == up) uu = 1; int y2 = x2, y3 = x3, y5 = x5, y7 = x7; if(i == 2) y2++; if(i == 3) y3++; if(i == 4) y2 += 2; if(i == 5) y5++; if(i == 6) y2++, y3++; if(i == 7) y7++; if(i == 8) y2 += 3; if(i == 9) y3 += 2; ans += dfs(x - 1, y2, y3, y5, y7, 0, uu); } if(!limit && !pd) f[x][x2][x3][x5][x7] = ans; return ans; } LL solve(LL x) { if(x == 0) return 0; len = 0; while(x) a[++len] = x % 10, x /= 10; LL ans = 0; memset(f, -1, sizeof(f)); for(int i = 0; i <= a[len]; i++) { bool h1 = 0, h2 = 0; if(i == 0) h1 = 1; if(i == a[len]) h2 = 1; int y2 = 0, y3 = 0, y5 = 0, y7 = 0; if(i == 2) y2++; if(i == 3) y3++; if(i == 4) y2 += 2; if(i == 5) y5++; if(i == 6) y2++, y3++; if(i == 7) y7++; if(i == 8) y2 += 3; if(i == 9) y3 += 2; ans += dfs(len - 1, y2, y3, y5, y7, h1, h2); } return ans; } int main() { scanf("%d", &n); LL x, y; scanf("%lld%lld", &x, &y); printf("%lld\n", solve(y - 1) - solve(x - 1)); return 0; }