[BZOJ1799][Ahoi2009]self 同类分布(数位dp)

题目描述

给出两个数 a,ba,b ,求出 [a,b][a,b] 中各位数字之和能整除原数的数的个数。

输入输出格式

输入格式:

 

一行,两个整数 aa 和 bb

 

输出格式:

 

一个整数,表示答案

 

输入输出样例

输入样例#1: 复制
10 19
输出样例#1: 复制
3

说明

对于所有的数据, 1 ≤ a ≤ b ≤ 10^{18}1ab1018

题解

  数位dp

  至于怎么判是否整除

  我们可以考虑枚举所有位之和是多少

  然后记录一下当前数模所有位之和的余数

  如果为$0$说明可行

 1 //minamoto
 2 #include<cstdio>
 3 #include<cstring>
 4 #define ll long long
 5 using namespace std;
 6 ll dp[25][205][205],a,b;
 7 int num[25],len;
 8 ll dfs(int pos,int p,int s1,int s2,bool flag){
 9     if(!pos) return s1==p&&s2==0;
10     if(s1>p||s1+pos*9<p) return 0;
11     if((~dp[pos][s1][s2])&&(!flag)) return dp[pos][s1][s2];
12     ll res=0;int lim=flag?num[pos]:9;
13     for(int i=0;i<=lim;++i)
14     res+=dfs(pos-1,p,s1+i,(s2*10+i)%p,flag&&i==lim);
15     if(!flag) dp[pos][s1][s2]=res;
16     return res;
17 }
18 ll solve(ll x){
19     len=0;
20     for(;x;x/=10) num[++len]=x%10;
21     if(!len) return 0ll;
22     ll res=0;
23     for(int i=1;i<=len*9;++i){
24         memset(dp,-1,sizeof(dp));
25         res+=dfs(len,i,0,0,1);
26     }
27     return res;
28 }
29 int main(){
30     //freopen("testdata.in","r",stdin);
31     scanf("%lld%lld",&a,&b);
32     printf("%lld\n",solve(b)-solve(a-1));
33     return 0;
34 }

 

posted @ 2018-08-27 09:36  bztMinamoto  阅读(170)  评论(0编辑  收藏  举报
Live2D