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 }
View Code

 题目链接:http://codeforces.com/contest/55/problem/D

posted on 2014-11-27 23:15  xiao_xin  阅读(301)  评论(0编辑  收藏  举报

导航