nowcoder A hard problem /// 数位DP
题目大意:
称一个数x的各个数位之和为f(x)
求区间L R之间 有多少个数x%f(x)==0
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define inc(i,j,k) for(int i=j;i<=k;i++) #define dec(i,j,k) for(int i=j;i>=k;i--) #define gcd(i,j) __gcd(i,j) #define mem(i,j) memset(i,j,sizeof(i)) const int N=2e5+5; int rd, dfn[2][15][50][50]; int fx, tot, a[15]; LL dp[2][15][50][50]; // dp[f][w][s][m] // f为1说明不是上界 此时为第w位数 // 剩下的数位总和为s 此时的数位总和%f(x)为m LL DFS(int f,int w,int s,int m) { if(w==0) return (s==0&&m==0); // 所有位都枚举过了则w=0 // 所有数位总和为fx则s=0 // x%fx==0则m=0 if(dfn[f][w][s][m]==rd) return dp[f][w][s][m]; dfn[f][w][s][m]=rd; LL res=0LL; int l=max(0,s-9*(w-1)), r=min((f ? 9:a[w]),s); for(int i=l;i<=r;i++) // 枚举当前位的数 res+=DFS(f|(i<a[w]),w-1,s-i,(m*10+i)%fx); // 之前不是上界 或 当前位不是上界 则到目前为止都不达上界 // 位数-1 剩余数位总和需减去当前位的数 更新余数 return dp[f][w][s][m]=res; } LL solve(int x) { mem(dp,0); mem(dfn,0); int tot=0; while(x) { a[++tot]=x%10; x/=10; } int all=tot*9; LL res=0LL; for(fx=1;fx<=all;fx++) // 枚举所有数位总和 ++rd, res+=DFS(0,tot,fx,0); //printf("%lld\n",res); return res; } int main() { int _; scanf("%d",&_); inc(i,1,_) { int l,r; scanf("%d%d",&l,&r); rd=0; printf("Case %d: ",i); printf("%lld\n",solve(r)-solve(l-1)); } return 0; }