hdu 3709

数位DP!!

题意:给一个很大的区间[x,y],(0 ≤ x ≤ y ≤ 1018).问:区间里面的数满足如下规则的有多少个?

规则:将数字放在天平上,天平能够平衡。天平的轴随意,力臂就是数字下标到天平轴的下标的距离。

思路:典型的数位DP,不过有一些技巧快速判断数字是不是满足规则。

定义:

区间分解:[X,Y]=[0,Y] -[0,X-1]

对于小于X的数:

sdig=sum(digit(i)){i=1..n,digit(i)表示数的第i个数字}

snum=sum(i*digit(i)){i=1..n}

每一次判断大数是不是平衡的,就看snum%sdig是不是0.

因为:如果将轴放在最高位的左边,那么天平将偏向一边,我们定义一个天平平衡度,就是snum.

如果天平平衡,那么snum=0

每次从高位向低位移动轴的时候,平衡度减小sdig,这个画画图就知道。于是判断能否整除就可以知道数字是不是平衡的。

View Code
 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 using namespace std;
 7 #define inf 1000000000
 8 int d[25];
 9 __int64 dp[18][180][1600];
10 //int dp[18][18*9+1][9*9*17+1];
11 __int64 dfs(int i,int sdig,int snum,bool flag)
12 {
13     //准备枚举i位时,数字和sdig,数的位权和snum
14     if(i==0)
15         if(sdig==0 || snum%sdig==0)return 1;
16         else return 0;
17     if(!flag && dp[i-1][sdig][snum]!=-1)
18         return dp[i-1][sdig][snum];
19     int limit;
20     __int64 sum;
21     if(flag)limit=d[i];
22     else limit=9;
23     sum=0;
24     for(int s=0;s<=limit;s++)
25         sum+=dfs(i-1,sdig+s,snum+s*(i-1),flag&&s==limit);
26 if(!flag)    dp[i-1][sdig][snum]=sum;
27 return sum;
28 }
29 int main()
30 {
31     int T;
32     __int64 A,B,SA,SB;
33     cin>>T;
34     memset(dp,-1,sizeof(dp));
35     while(T--)
36     {
37     cin>>A>>B;
38     A--;
39     d[0]=0;
40     do{    d[++d[0]]=A%10;    A/=10;}while(A);
41     SA=dfs(d[0],0,0,1);
42     d[0]=0;
43     do{    d[++d[0]]=B%10;    B/=10;}while(B);
44     SB=dfs(d[0],0,0,1);
45 
46     cout<<SB-SA<<endl;
47     }
48     return 0;
49 }

 

posted on 2012-04-15 16:52  kevinkitty  阅读(450)  评论(0编辑  收藏  举报

导航