CodeForces - 55D Beautiful numbers(數位DP+離散化)
阿新 • • 發佈:2018-11-10
題目
題意:
一個數能被其數位上非0的數整除,稱為beautiful number;求區間beautiful number數的數目;
思路:
能被數位上的每個數整除的話,意思就是該數能被數位上所有非0數的最小公倍數整除。
考慮數位DP,dp[i][j][k],表示第i位,lcm為j,取模後為k。lcm(1,2,3,4...9)=2520,所以dp[20][2520][2520];但是考慮到1-2520裡面的數很多並非有意義的數,比如17,31。所以我們可以離散化最小公倍數。所以二維陣列開55就夠了。找出有意義的公倍數,並依次標號(1,2,3...)。剩下的就是數位DP。
注意:
離散化陣列要開2520大小。
在算數對lcm取模時,我們可以對將該數mod2520.
#include<bits/stdc++.h> using namespace std; typedef long long ll; int a[20]; int b[2530]; ll dp[20][55][2530]; void init() { int tot=1; for(int i=1;i<=2520;i++) if(2520%i==0) b[i]=tot++; } int _lcm(int a,int b) { return a/__gcd(a,b)*b; } ll dfs(int pos,int lcm,int mod,bool limit) { if(pos==-1) return (mod%lcm==0); if(!limit&&dp[pos][b[lcm]][mod]!=-1) return dp[pos][b[lcm]][mod]; int up=limit?a[pos]:9; ll ans=0; for(int i=0;i<=up;i++) { if(i==0) ans+=dfs(pos-1,lcm,mod*10%2520,limit&&i==up); else ans+=dfs(pos-1,_lcm(lcm,i),(mod*10+i)%2520,limit&&i==up); } if(!limit) dp[pos][b[lcm]][mod]=ans; return ans; } ll slove(ll n) { int tot=0; while(n) { a[tot++]=n%10; n/=10; } return dfs(tot-1,1,0,true); } int main() { ios::sync_with_stdio(false); memset(dp,-1,sizeof(dp)); init(); int t; cin>>t; while(t--) { ll a,b; cin>>a>>b; /// cout<<slove(b)-slove(a-1)<<endl; printf("%I64d\n",slove(b)-slove(a-1)); } return 0; }