【bzoj1799】【AHOI2009】【同类分布】【数位dp】

Description

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

Input

Output

Sample Input

10 19

Sample Output

3

HINT

【约束条件】1 ≤ a ≤ b ≤ 10^18

题解:

         枚举模数p.

         设f[i][j][k][g]表示第i位,前i位的和为j,当前模p的值为k,到第i位是否比原数小.

         枚举所有状态向后转移即可.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
ll pow[20],f[20][200][200][2],l,r;
int p[20],num,mx;
ll cal(ll x){
   ll ans=0;mx=0;num=0;
   while (x){p[++num]=x%10;x/=10;}
   for (int i=1;i<=num/2;i++) swap(p[i],p[num-i+1]);
   for (int i=1;i<=num;i++) mx+=9;
   for (int md=1;md<=mx;md++){
     memset(f,0,sizeof(f));
     f[0][0][0][1]=1;
	 for (int i=0;i<num;i++)
       for (int j=0;j<=md;j++)
         for (int k=0;k<md;k++)
           for (int g=0;g<=1;g++)
             if (f[i][j][k][g])
               for (int a=0;a<=9;a++){
                 int x,y,z;
                 if (g&&a>p[i+1]) continue;
                 x=j+a;y=(k+(pow[num-(i+1)]%(ll)md)*a%md)%md;
                 z=(g&&(a==p[i+1]))?1:0;
                 f[i+1][x][y][z]+=f[i][j][k][g];
               }
     ans+=f[num][md][0][0]+f[num][md][0][1];
   } 
   return ans;
}
int main(){
  pow[0]=1;
  for (int i=1;i<=18;i++) pow[i]=pow[i-1]*(ll)10;
  scanf("%lld%lld",&l,&r);
  printf("%lld\n",cal(r)-cal(l-1)); 
  
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值