一、引例
#1033 : 交错和
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个数 x,设它十进制展从高位到低位上的数位依次是 a0, a1, ..., an - 1,定义交错和函数:
f(x) = a0 - a1 + a2 - ... + ( - 1)n - 1an - 1
例如:
f(3214567) = 3 - 2 + 1 - 4 + 5 - 6 + 7 = 4
给定 l, r, k,求在 [l, r] 区间中,所有 f(x) = k 的 x 的和,即:
1405402477702.png
输入
输入数据仅一行包含三个整数,l, r, k(0 ≤ l ≤ r ≤ 1018, |k| ≤ 100)。
输出
输出一行一个整数表示结果,考虑到答案可能很大,输出结果模 109 + 7。
提示
对于样例 ,满足条件的数有 110 和 121,所以结果是 231 = 110 + 121。
1 /*
2 ************************************交错和***********************************************3 ******************************by JA/C++ 2015-1-19****************************************4 */
5
6
7 #include
8 #include
9 long long mod = 1000000007;10 long long base[20];11 long long l, r, k, bit[20], bt, yy;12 structnode {13 long long s, n;//s代表数字和,n代表数字个数
14 };15 node dp[20][400];//状态转移
16 node dfs(long long pos, long long target, long long limit)//数位dp,基本可以算是模板啦
17 {18 node t;19 t.s = t.n = 0;20 if (pos == 0) { //处理到最后一位,直接判断返回
21 if (target == 100)22 t.n = 1;23 returnt;24 }25 if ((limit == 0) && (dp[pos][target].n != -1)) returndp[pos][target];26 long long tail = limit ? bit[pos] : 9;27 long long sgn = ((yy - pos) % 2) ? (-1) : (1);//确定符号
28 long longhead;29 if (pos == yy)head = 1;30 else head = 0;//确定搜索的起点和终点
31 for (long long i= head; i <= tail; i++)32 {33 node tmp = dfs(pos - 1, target - i*sgn, (limit == 1) && (i ==bit[pos]));34 if ((tmp.n)>0){35 t.n +=tmp.n;36 long longq;37 q = ((((tmp.n%mod)*base[pos]) % mod)*i) % mod;//结果的同余处理
38 t.s += (tmp.s) %mod;39 t.s %=mod;40 t.s +=q;41 t.s %= mod;//每一步都要同余
42 }43 }44 if (limit == 0) dp[pos][target] =t;45 returnt;46 }47 long long cal(long long x, long longy)48 {49 long long ans = 0;50 if (x == -1) return 0;51 if (x == 0) return 0;52 bt = 0;53 while(x)54 {55 bt++;56 bit[bt] = x % 10;57 x /= 10;58 }59 for (yy = 1; yy <= bt; yy++){60 memset(dp, -1, sizeofdp);61 ans += dfs(yy, y + 100, yy == bt).s;//对于每个长度为yy的数字进行处理
62 ans = (ans + mod) %mod;63 }64 returnans;65 }66 intmain()67 {68 base[1] = 1;69 for (int i = 2; i <= 19; i++)70 base[i] = (base[i - 1] * 10) %mod;71 scanf("%lld%lld%lld", &l, &r, &k);72 //scanf_s("%lld%lld%lld", &l, &r, &k);
73 {74 printf("%lld", (cal(r, k) - cal(l - 1, k) + mod) %mod);75 }76 return 0;77 }
View Code
二、思路分析
给定取值范围,要求区间内数的交错和为给定数,需要用到数位dp,记忆搜索以及同余定理。
1.记忆化搜索写的时候要将相同交错和的个数,相同交错和的数字和分别进行dp。
2.对于一位数字和两位数字的计算方式并不相同,要分数字的位数进行讨论。
3.由于结果可能比较大,每一步都需要使用同余定理。
三、数位dp模板
1 const intMAX_DIGITS, MAX_STATUS;2 LL f[MAX_DIGITS][MAX_STATUS], bits[MAX_DIGITS];3
4 LL dfs(int position, int status, bool limit, boolfirst)5 {6 if (position == -1)7 return s ==target_status;8 if (!limit && !first && ~f[position][status])9 returnf[position][status];10 int u = limit ?bits[position] : MAX_BITS;11 LL ret = 0;12 for (int i = 0; i <= u; i++)13 {14 ret += dfs(position - 1, next_status(status, i), limit && i == u, first && !i);15 }16 return limit || first ? ret : f[pos][status] =ret;17 }18
19 LL calc(LL n)20 {21 CLR(f, -1);22 int len = 0;23 while(n)24 {25 bits[len++] = n % 10;26 n /= 10;27 }28 return dfs(len - 1, 0, true, true);29 }30
31 intmain()32 {33 //freopen("0.txt", "r", stdin);
34 LL a, b;35 while (cin >> a >>b)36 cout << calc(b) - calc(a - 1) <
四、记忆化搜索
记忆化搜索=搜索的形式+动态规划的思想
参考文献
1.算法合集之《浅谈数位类统计问题》——刘聪
2.推酷《数位dp模板》