http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2346
不知道算什么题,好像是数位dp,不过在切递推的题,所以这题应该算是递推。
首先要预处理出dp[i][j][k][p],表示一共有i位数字,其中数字和mod p余j而且这个数mod p余k的个数。然后就是枚举每一位,分段处理出结果。
代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 6 using namespace std; 7 8 typedef long long LL; 9 const int N = 12; 10 const int M = 55; 11 LL dp[N][M][M][M], ep[N]; 12 13 void PRE() { 14 for (int i = 0; i < M; i++) dp[0][0][0][i] = 1; 15 for (int i = 0; i < N - 1; i++) { 16 for (int j = 0; j < M; j++) { 17 for (int k = 0; k < M; k++) { 18 for (int p = 1; p < M; p++) { 19 for (int q = 0; q < 10; q++) { 20 dp[i + 1][(j + q) % p][(k * 10 + q) % p][p] += dp[i][j][k][p]; 21 } 22 } 23 } 24 } 25 } 26 ep[0] = 1; 27 for (int i = 0; i < N - 1; i++) ep[i + 1] = ep[i] * 10; 28 //cout << dp[1][0][0][1] << endl; 29 //cout << dp[1][0][0][2] << endl; 30 //cout << dp[1][0][0][3] << endl; 31 //cout << dp[3][1][1][4] << endl; 32 } 33 34 LL cal(int x, int k) { 35 int p = 0, dgs = 0; 36 if (k >= M) return 0; 37 LL ret = 0; 38 while (x >= ep[p]) p++; 39 while (p > 0) { 40 p--; 41 int cdg = x / ep[p] % 10; 42 for (int i = 0; i < cdg; i++) { 43 ret += dp[p][(k - (dgs + i) % k) % k][(k - (x / ep[p + 1] * 10 + i) * ep[p] % k) % k][k]; 44 } 45 dgs += cdg; 46 } 47 return ret + dp[0][(k - dgs % k) % k][(k - x % k) % k][k]; 48 } 49 50 int main() { 51 PRE(); 52 int T, n, m, k; 53 cin >> T; 54 while (T-- && cin >> n >> m >> k) cout << cal(m, k) - cal(n - 1, k) << endl; 55 return 0; 56 }
——written by Lyon