題目大意:
計算給定範圍中有多少個漂亮數。
一個正整數是 漂亮數 ,當且僅當它能夠被自身的各非零數字整除。
題解:
首先要知道一個結論:一個數如果能被一些數整除,那麼一定會被這些數的最小公倍數整除。
因此我們可以求出lcm(1,2,3....9)=2520.
對於任何一個數 num,num = 2520k + num',我們有 num % 2520 % t = num' % t (t = 1,2,3, ... , 9),
具體證明:https://www.cnblogs.com/Blogggggg/p/7764023.html
這樣我們再維護數的時候就可以對2520取餘了。
因此定義狀態dp[pos][num][lcm]表示枚舉到pos位,前面數位的形成的數對2520取餘的結果num,以及前面數位的數形成最小公倍數lcm.
最後只需要判斷num%lcm==0.
但是這樣的需要的空間是20*2520*2520*8/1024/1024=968M大於給的262M內存了。
因此我們需要考慮把最後一維形成的最小公倍數離散化一下,因爲小於2520,且能整除2520的數只有48個。
這樣空間就存的下了。
代碼實現:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cstdlib> #include <vector> using namespace std; #define LL long long const int MOD = 2520; LL dp[20][50][2550]; int dis[20]; int Hash[2550]; LL gcd(LL a, LL b) { return b?gcd(b,a%b):a; } LL dfs(int len, int num, int lcm, bool flag) { if(-1==len) return num%lcm == 0; if(!flag && ~dp[len][Hash[lcm]][num]) return dp[len][Hash[lcm]][num]; LL ans = 0; int end = flag?dis[len]:9; for(int i=0; i<=end; i++) ans += dfs(len-1, (num*10+i)%MOD, i?lcm*i/gcd(lcm,i):lcm, flag&&i==end); if(!flag) dp[len][Hash[lcm]][num] = ans; return ans; } LL solve(LL n) { int pos = 0; while(n) { dis[pos++] = n%10; n /= 10; } return dfs(pos-1, 0, 1, 1); } int main() { int T; scanf("%d", &T); int cnt = 0; for(int i=1; i<=MOD; i++) if(MOD%i == 0) Hash[i] = cnt++; memset(dp, -1, sizeof(dp)); while(T--) { long long l, r; scanf("%lld%lld", &l, &r); printf("%lld\n", solve(r)-solve(l-1)); } return 0; }
cf55D——數位dp+離散化+構造
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.