数位dp

发布时间 2023-10-29 20:22:48作者: 不o凡
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N=250,mod=998244353;
int f[N][2000];//长度为i时,前pos-1项的和为j的合法数
string s;

//pos位置,sum==mark目标,limit限制,isnum是否存在数字
int dfs(int pos,int sum,bool limit,bool isnum){
  int up=limit?s[pos]-'0':9;//如果有限制那么最多只能枚举到该位置,否则会超出n的范围
  if(pos==(int)s.size()-1){//到达终点
    int cnt=0;
    for(int i=1;i<=up;i++)//不要超过n的范围
      cnt+=sum%i==0;
    return cnt;
  }
  if(isnum&&!limit&&f[pos][sum]!=-1) return f[pos][sum];//记忆化
  int res=0;
  //只有前面都为前导0才可以
  if(pos<(int)s.size()-2&&!isnum) res=dfs(pos+1,0,false,false);//跳过,注意边界
  for(int i=1-isnum;i<=up;i++){//范围,以及起始边界
    res=(res+dfs(pos+1,sum+i,i==up&&limit,true))%mod;//每一个位置的合法数都要枚举
  }
  if(isnum&&!limit) f[pos][sum]=res;//如果存在数,且在合法范围内,记忆化
  return res;

}


bool check(string l){
  int last=l.back()-'0';
  if(last==0) return 0;
  int sum=0;
  for(int i=0;i<(int)l.size()-1;i++) sum+=l[i]-'0';
  return sum%last?0:1;
}

int main()
{
  string l,r;
  cin>>l>>r;
  s=r;
  memset(f,-1,sizeof f);
  int ansr=dfs(0,0,true,false);

  s=l;
  memset(f,-1,sizeof f);
  int ansl=dfs(0,0,true,false);

  cout<<((ansr-ansl+check(l))%mod+mod)%mod;
  return 0;
}