HDU 4389 X mod f(x) (数位dp)
终于把这题搞出来了。。。前后看了半一星期。比赛堆积的题目在减少。。。加油!
数位dp,f[i][sum][mod][res]表示前i位,和为sum,模为mod,sum%mod结果为res的状态个数。f[i+1][sum+k][mod][(res*10 + k)%mod] += f[i][sum][mod][res];
予处理出所有的f[i][sum][mod][res], 然后从高到低逐位统计。比如当前位为a_i,则枚举当前位为0...(a_i-1) 这些数,i位往后的数的所有状态已经预处理出来了。。。所以出现 %mod == 0的情况直接累加就可以。。。最后单独处理一下最低位。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <vector> 5 #include <cstring> 6 #include <algorithm> 7 #include <string> 8 #include <set> 9 #include <ctime> 10 #include <queue> 11 #include <map> 12 #include <functional> 13 #include <numeric> 14 #include <sstream> 15 16 #define CL(arr, val) memset(arr, val, sizeof(arr)) 17 #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) 18 #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) 19 #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) 20 #define L(x) (x) << 1 21 #define R(x) (x) << 1 | 1 22 #define MID(l, r) (l + r) >> 1 23 #define Min(x, y) x < y ? x : y 24 #define Max(x, y) x < y ? y : x 25 #define E(x) (1 << (x)) 26 27 const int eps = 1e-4; 28 typedef long long LL; 29 const int inf = ~0u>>2; 30 using namespace std; 31 32 const int N = 83; 33 34 int f[12][N][N][N]; 35 int ten[15]; 36 37 38 void init() { 39 int i, sum, mod, res, k, j; 40 ten[0] = 1; 41 for(i = 1; i <= 10; ++i) ten[i] = ten[i-1]*10; 42 CL(f, 0); 43 for(i = 0; i < 10; ++i) { 44 for(j = 1; j < N; ++j) f[1][i][j][i%j] = 1; 45 } 46 47 for(i = 1; i < 9; ++i) { 48 for(sum = 0; sum < N; ++sum) { 49 for(mod = 1; mod < N; ++mod) { 50 for(res = 0; res < N; ++res) { 51 if(!f[i][sum][mod][res]) continue; 52 for(k = 0; k < 10 && sum + k < N; ++k) 53 f[i+1][sum + k][mod][(res*10 + k)%mod] += f[i][sum][mod][res]; 54 } 55 } 56 } 57 } 58 } 59 60 int a[15]; 61 62 int Do(int x) { 63 if(x <= 10) return x; 64 int tsum = 0, i, j, n = 0, u; 65 int mod, sum, num, res, ans = 0; 66 67 for(u = x ; u > 0; u /= 10) a[++n] = u%10, tsum += u%10; 68 69 for(mod = 1; mod <= 9*n; ++mod) { //枚举取模,也就是所有数位的和 70 if(mod > x) break; 71 sum = mod; 72 num = 0; 73 for(i = n; i > 1; --i) { 74 for(j = 0; j < a[i] && j <= sum; ++j) { //从0...(a_i - 1)枚举。第i位的数 75 for(res = 0; res < mod; ++res) { //res 表示i位以后的数位和取模得到的值 76 if((num + j*ten[i-1] + res)%mod == 0) { //根据同余公式 77 ans += f[i-1][sum - j][mod][res]; 78 } 79 } 80 } 81 sum -= a[i]; 82 num += a[i]*ten[i-1]; 83 } 84 } 85 while(1) { //单独处理最低位 86 if(x%tsum == 0) ans++; 87 if(x%10 == 0) break; 88 x -- ; tsum --; 89 } 90 return ans; 91 } 92 93 int main() { 94 freopen("data.in", "r", stdin); 95 96 init(); 97 int t, a, b, cas = 0; 98 scanf("%d", &t); 99 while(t--) { 100 scanf("%d%d", &a, &b); 101 printf("Case %d: %d\n", ++cas, Do(b) - Do(a - 1)); 102 } 103 return 0; 104 }