#数位dp,卡常优化#jzoj 1664 洛谷 4127 codevs 2232 同类分布

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/82015794

题目

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


分析

f [ i ] [ s ] [ m ] [ 0 / 1 ] i , s mod s u m = m 0 1

f [ i + 1 ] [ s + k ] [ ( m 10 + k ) mod s u m ] [ c ( k == t [ i ] ) ] + = f [ i ] [ s ] [ m ] [ c ] ;

然后其实得到这个最后答案为
f [ n ] [ s u m ] [ 0 ] [ 0 ] + f [ n ] [ s u m ] [ 0 ] [ 1 ]
,然后卡卡常就没什么了


代码(自行卡常)

#include <cstdio>
#include <algorithm>
#include <cstring>
typedef unsigned long long ull;
ull a,b,f[2][181][181][2];
ull answer(ull x){
    ull X=x; int t[21],n=0;
    while (X) t[++n]=X%10,X/=10; 
    std::reverse(t+1,t+1+n); ull ans=0;
    for (register int sum=1;sum<=n*9;sum++){
        memset(f[0],0,sizeof(f[0])); bool x=0;
        f[0][0][0][1]=1;
        for (register int i=0;i<n;i++){
            x^=1; memset(f[x],0,sizeof(f[x]));
            for (register int s=0;s<=sum;s++)
            for (register int m=0;m<sum;m++)
            for (register int c=0;c<2;c++){
                long long res=f[x^1][s][m][c];
                if (!res) continue;//得不到答案
                for (register int k=0;k<=(c?t[i+1]:9);k++){
                    if (s+k>sum) break;
                    else f[x][s+k][(m*10+k)%sum][c&(k==t[i+1])]+=res;
                }
            }
        }
        ans+=f[x][sum][0][0]+f[x][sum][0][1];
    }
    return ans;
}
int main(){
    scanf("%llu%llu",&a,&b);
    return !printf("%llu",answer(b)-answer(a-1));//前缀和
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/82015794