题意:给出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的数的个数
*/