[Ahoi2009]self 同类分布

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

这道题把上界状态编入方程中时空复杂度才能过

算见注

#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;

int f[2][20][170][170],vis[2][20][170][170];
int d[20],ld;
int p,tim;//模数,即枚举的数字和;tim是时间戳

int dp(int fl,int dg,int s,int md){
    if(dg==0)return s==0&&md==0;
    if(vis[fl][dg][s][md]==tim)return f[fl][dg][s][md];
    vis[fl][dg][s][md]=tim;
    int res=0;
    //由于是自更新,需要知道当前位的取值范围
    int l=max(0ll,s-(dg-1)*9), r=min(s,(fl?9:d[dg]));
    for(int i=l;i<=r;i++){
        res+=dp(fl|(i<d[dg]),dg-1,s-i,(md*10+i)%p);
    }
    return f[fl][dg][s][md]=res;
}
int calc(int m){
    ld=0;
    while(m)d[++ld]=m%10,m/=10;
    //reverse(d+1,d+ld+1);
    int res=0;
    for(p=1;p<=ld*9;p++){
        ++tim;
        res+=dp(0,ld,p,0);
    }
    return res;
}

signed main(){
    int a,b;
    scanf("%lld%lld",&a,&b);
    printf("%lld",calc(b)-calc(a-1));
    return 0;
}
/*
 * fl:0表示满上界,1表示未满
 * dg:首位。这里是颠倒的,即1是最高位
 * s:数字和;md:余数
 * 状态表示,当前的最高位是从低到高第dg位,且第1-dg位的数字和为s,
 * 第dg+1~ld位的余数为md的数的个数
 */

原文地址:https://www.cnblogs.com/sshwy/p/10995777.html