CodeForces 55D 数位dp三(某数能被它每位数整除)
dfs(pos,sum,nlcm,flag)
pos表示到第几位;
sum表示前几位表示的数,因为太大可以mod所有数的最小公倍数2520;
nlcm表示前几位的最小公倍数,最大只有2520,但还是太多需要离散化;
flag表示有没有上限。
dp[pos][sum][nlcm];
1 #include<stdio.h> 2 #include<string.h> 3 #define MOD 2520 4 int num[25],t[200],hash[2550]; 5 long long dp[25][2550][50]; 6 int gcd(int x,int y) 7 { 8 if (y==0) return x; 9 return gcd(y,x%y); 10 } 11 int lcm(int x,int y) 12 { 13 return x/gcd(x,y)*y; 14 } 15 long long dfs(int pos,int sum,int nlcm,int flag) 16 { 17 if (pos==0) { 18 if (sum%t[nlcm]==0) return 1; 19 return 0; 20 } 21 if (!flag&&dp[pos][sum][nlcm]!=-1) 22 return dp[pos][sum][nlcm]; 23 long long ans=0; 24 int i,temp,x,y; 25 temp=flag?num[pos]:9; 26 for (i=0;i<=temp;i++) 27 { 28 x=(sum*10+i)%MOD; 29 y=i?hash[lcm(t[nlcm],i)]:nlcm; 30 ans+=dfs(pos-1,x,y,flag&&(i==temp)); 31 } 32 if (!flag) 33 dp[pos][sum][nlcm]=ans; 34 return ans; 35 } 36 long long solve(long long x) 37 { 38 // if (x==0) return 0; 39 int tmp=0; 40 while (x!=0) 41 { 42 num[++tmp]=x%10; 43 x/=10; 44 } 45 return dfs(tmp,0,1,1); 46 } 47 int main() 48 { 49 int cnt=0,i,T; 50 long long l,r; 51 memset(dp,-1,sizeof(dp)); 52 memset(hash,0,sizeof(hash)); 53 for (i=1;i<=MOD;i++) 54 if (MOD%i==0) 55 { 56 t[++cnt]=i; 57 hash[i]=cnt; 58 } 59 scanf("%d",&T); 60 while (T--){ 61 scanf("%I64d%I64d",&l,&r); 62 printf("%I64d\n",solve(r)-solve(l-1)); 63 } 64 }