bzoj 1799: [Ahoi2009]self 同类分布 (数位DP)

来源:互联网 发布:javabean连接数据库 编辑:程序博客网 时间:2024/05/16 01:24

题目描述

传送门

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

题解

枚举数位和sum,然后用数位DP计算。
f[i][j][k][0/1]表示到第i位数位和为j,在模sum意义下的余数为k,是否卡上界的数的个数。
ans=189i=1f[cnt][sum][0][0]+f[cnt][sum][0][1]cnt

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 203#define LL long longusing namespace std;LL f[21][N][N][2],l,r;int cnt,a[N];LL solve(LL x){    if (x==0) return 0;    cnt=0;    while (x!=0) {        a[++cnt]=x%10;        x/=10;    }    reverse(a+1,a+cnt+1);    LL ans=0;    for (int sum=1;sum<=18*9;sum++){        memset(f,0,sizeof(f));        f[0][0][0][1]=1;        for (int i=0;i<=cnt;i++)         for (int j=0;j<=18*9;j++)          for (int k=0;k<=18*9;k++)           for (int l=0;l<=1;l++)            if (f[i][j][k][l]){                for (int t=0;t<=9;t++){                    if (l==1&&t>a[i+1]) break;                    f[i+1][j+t][(k*10+t)%sum][(l==1&&t==a[i+1])?1:0]+=f[i][j][k][l];                 }            }        ans+=f[cnt][sum][0][0]+f[cnt][sum][0][1];    }    return ans;}int main(){    freopen("a.in","r",stdin);    scanf("%lld%lld",&l,&r);    printf("%lld\n",solve(r)-solve(l-1));   }