hdu3709(数位dp)

求区间[l,r]内有多少个数的满足:   选一个位为中点,是的左边的数到该位的距离等于右边的位到该位的距离。     

比如4139  选择3位中点, 那么左边的距离是 4 * 2 + 1 * 1 , 右边的距离是9 * 1

想了半天,想到了枚举哪一位作为中点, 然后进行数位dp, 但是样例错了, 忽然想到会重复啊,就百度了一下

原来只有0在枚举中点时会重复,其他的数有且只有一个中点是的左边的距离等于右边的距离

所以只要最后ans-len+1即可

 1 #include <functional>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <string.h>
 5 #include <stdio.h>
 6 #include <math.h>
 7 #include <string>
 8 #include <vector>
 9 #include <queue>
10 #include <stack>
11 #include <set>
12 #include <map>
13 #pragma warning(disable:4996)
14 using namespace std;
15 typedef long long LL;
16 const int INF = 0x7fffffff;
17 const int mod = 2520;
18 LL dp[22][22][4000];
19 int num[22];
20 
21 LL dfs(int cur, int mid, int diff, bool flag)
22 {
23     if (cur == 0) return diff == 2000;
24     if (!flag && dp[cur][mid][diff] != -1)
25         return dp[cur][mid][diff];
26     LL ret = 0;
27     int end = flag ? num[cur] : 9;
28     for (int i = 0; i <= end; ++i)
29     {
30         int newDiff = diff;
31         if (cur > mid)
32             newDiff += (cur - mid) * i;
33         else if (cur < mid)
34             newDiff -= (mid - cur) * i;
35         ret += dfs(cur - 1, mid, newDiff, i == end && flag);
36     }
37     if (!flag)
38         dp[cur][mid][diff] = ret;
39     return ret;
40 }
41 LL calc(LL n)
42 {
43     int len = 0;
44     while (n)
45     {
46         num[++len] = n % 10;
47         n /= 10;
48     }
49     LL ret = 0;
50     
51     for (int i = 1; i <= len; ++i)
52         ret += dfs(len, i, 2000,true);
53     //0每次枚举中点时都被计算进去了,所以要剪掉
54     return ret - len + 1;
55     
56 }
57 int main()
58 {
59     memset(dp, -1, sizeof(dp));
60     int t;
61     LL l, r;
62     scanf("%d", &t);
63     while (t--)
64     {
65         scanf("%I64d%I64d", &l, &r);
66         if (l == 0)
67             printf("%I64d
", calc(r));
68         else
69             printf("%I64d
", calc(r) - calc(l - 1));
70     }
71         return 0;
72 }
View Code
原文地址:https://www.cnblogs.com/justPassBy/p/4940720.html