题意:给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。
思路:数位dp,比较容易想到是数位dp,关键是dp式比较难想到,数位dp说到底是一个记忆化搜索的过程,dp式是一个记忆数组,对于一类数来说,对应了一个dp式,并且他们的答案是一样的,那么可以通过只对一个经行搜索然后得到全部的答案,这其实就是一个状态,这个状态首先要保证与其他状态没有交集,并且要保证状态数不能过多,否则记忆化效果不好,比如1e18个数用1e5个状态来表示显然可以大大降低复杂度,时间上是没有问题的,但是如果状态答道了1e15就是一个非常糟糕的状态表示了,这个题的难点就是找状态,dp[pos][sum][v],第一维表示数位不用说,第二维表示前pos位的数位和,v表示这个数%mod的值,这个mod是枚举的,从1-162枚举, 比如 123xxxx枚举mod=5对应的dp式为dp[4][6][123%5],显然对于前3位和为6并且模的结果为3的状态的所有数来说答案是一样的,这里有一点,这里说的”答案“ 是指前几位已经确定,后面几位不确定,但是由已确定的前几位可以推出后面几位不确定的所有情况中可行的情况,比如123xx 一共存在100种可能性,其中12345是可行的,而12346是不可行的
AC代码:
#include "iostream" #include "iomanip" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #pragma comment(linker, "/STACK:102400000,102400000") #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a,x) memset(a,x,sizeof(a)) #define step(x) fixed<< setprecision(x)<< #define mp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define ll long long #define endl (" ") #define ft first #define sd second #define lrt (rt<<1) #define rrt (rt<<1|1) using namespace std; const ll mod=1e9+7; const ll INF = 1e18+1LL; const int inf = 1e9+1e8; const double PI=acos(-1.0); const int N=1e5+100; ll dp[18][162][162], bit[20]; ll dfs(int limit, int pos, int sum, int v, int mod){ if(sum+pos*9+9<mod || sum>mod) return 0; if(pos==-1) return sum==mod && v==0; if(dp[pos][sum][v]!=-1 && !limit) return dp[pos][sum][v]; int up=limit?bit[pos]:9; ll ans=0; for(int i=0; i<=up; ++i){ ans+=dfs(limit&&i==bit[pos], pos-1, sum+i, (v*10+i)%mod, mod); } if(!limit) dp[pos][sum][v]=ans; return ans; } ll solve(ll x){ int p=0; while(x){ bit[p++]=x%10; x/=10; } ll ret=0; for(int i=1; i<=p*9; ++i){ mem(dp,-1); ret+=dfs(1,p-1,0,0,i); } return ret; } int main(){ ll a,b; scanf("%lld%lld",&a, &b); printf("%lld ",solve(b)-solve(a-1)); return 0; }