[AHOI2009]同类分布

题目描述

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

输入格式

一行,两个整数a和b

输出格式

一个整数,表示答案

输入输出样例

输入 #1

10 19

输出 #1

3

说明/提示

对于所有的数据,1≤ab≤10^18

  1. 记录pos,sum(数字各位上的数的和),st(原数),limit

这里st可达到1e18显然是不能作为dp转移的下标直接记录的

所以我们考虑取模

我们最理想的模数当然是把每次搜到最后得到的数字各个位数之和

但是我们发现在这个过程中sum是发生变化的

所以我们就应该以一个定值作为模数

那好,我们虽然不知道最后各位之和的结果,我们枚举总可以吧

我们只需要枚举所有的各位数字之和作为模数

最后判断sum和枚举的mod相等并且st%sum=0的数就是符合题意的答案

#include<bits/stdc++.h>
using namespace std;
#define int long long
int l,r;
int len,mod;
int dp[20][200][200],a[20];
int dfs(int pos,int sum,int st,int limit)
{
    if(pos==0&&sum==0) return 0;

    if(pos==0) return st==0&&sum==mod?1:0;

    if(!limit&&dp[pos][sum][st]!=-1) return dp[pos][sum][st];

    int res=0, up=limit ? a[pos] : 9;

    for(int i=0; i<=up; i++)
        res+=dfs(pos-1,sum+i,(10ll*st+i)%mod, limit&&i==up);

    return limit?res:dp[pos][sum][st]=res;
}
int cal(int x)
{
    len=0;

    while (x) a[++len]=x%10,x/=10;

    int ret=0;

    for(mod=1; mod<=9*len; mod++)
    {
        memset(dp,-1,sizeof dp);
        ret+=dfs(len,0,0,1);
    }
    return ret;
}
signed main()
{
    cin>>l>>r;

    cout<<cal(r)-cal(l-1)<<"\n";

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值