数位dp
https://vjudge.net/contest/237022#problem/E
题意:给出区间【A,B】,询问该区间中有多少数满足该数能整除其数位之和?
提示:数位dp状态为dp[pos][sum][mod][res],其中pos表示当前在第几位,sum表示当前的数位之和,mod表示模,res表示当前的构成的数%mod的值。
当pos为最后一位,且sum == mod && res == 0时,返回1;否则返回0;
其中,mod从1至81枚举,对于每个mod求一次dfs。
注意dp数组只用初始化一次,因为不同case中用到的dp数组是相同的,不然会超时。另外,数组尽量开刚刚好,否则会爆内存。
参考以下博客:https://blog.csdn.net/my_acm_dream/article/details/41910839
1 //#include<bits/stdc++.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 #include <string> 7 #include <cmath> 8 #include <cstdlib> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <vector> 13 #include <set> 14 #include <bitset> 15 #include <iomanip> 16 #define ms(a, b) memset(a, b, sizeof(a)); 17 using namespace std; 18 typedef long long LL; 19 typedef pair<int, int> pii; 20 const int INF = 0x3f3f3f3f; 21 const int maxn = 1e3 + 10; 22 const int MAXN = 2e4 + 10; 23 const double eps = 1e-8; 24 const int mod = 1e9 + 7; 25 int a, b; 26 int dp[11][82][82][82]; 27 int bit[11]; 28 29 int dfs(int pos, int sum, int mod, int res, int f) { 30 if(pos < 1) return sum == mod && res == 0; 31 if(!f && dp[pos][sum][mod][res] != -1) return dp[pos][sum][mod][res]; 32 int last = f ? bit[pos] : 9; 33 int ans = 0; 34 for(int i = 0; i <= last; i++) { 35 ans += dfs(pos-1, sum+i, mod, (res*10+i)%mod, f&&i==last); 36 } 37 if(!f) dp[pos][sum][mod][res] = ans; 38 return ans; 39 } 40 41 int solve(int n) { 42 int len = 0; 43 while(n) { 44 bit[++len] = n % 10; 45 n /= 10; 46 } 47 int cnt = 0; 48 for(int i = 1; i <= 81; i++) { 49 cnt += dfs(len, 0, i, 0, 1); 50 } 51 return cnt; 52 } 53 54 55 int main() { 56 #ifdef local 57 freopen("case.in", "r", stdin); 58 // freopen("case.out", "w", stdout); 59 #endif 60 // ios::sync_with_stdio(false); 61 // cin.tie(0); 62 int T; 63 scanf("%d", &T); 64 int kase = 0; 65 ms(dp, -1); 66 while(T--) { 67 scanf("%d%d", &a, &b); 68 int ans = solve(b) - solve(a-1); 69 printf("Case %d: %d\n", ++kase, ans); 70 } 71 // solve(); 72 return 0; 73 }