【上海交大oj】数学题3(数位dp)

1398. 数学题3

题目描述

给定一个数字,他在十进制下从高位到低位一次是n0, n1, n2, n3,...

那么定义它的“差和”为n0-n1+n2-n3+...

如:十进制数字abcdefg,每个字母代表一个位,那么差和为a-b+c-d+e-f+g。

所以十进制数字1234567差和为1-2+3-4+5-6+7=4

现在给你们一个闭区间[m, n],请求出区间内差和为x的数字个数。

输入格式

输入只有一行,三个数字,m n x

30%: 0<= m <= n <=10^3, 50%: 0<= m <= n <=10^8, 100%: 0<= m <= n <=10^18

-100<= x <=100

输出格式

输出只有一个数字,表示区间内差和为x的数字的总和mod1000000007的结果。

Sample Input

100 111 1

Sample Output

211

这题不会做,妥妥的。为了看懂助教的代码,费了好大劲儿,干脆加点注释,防止以后有用。要点:1.由于区间太大,无法遍历,所以要把一个数按位处理,有点转化为数组的意思。2.动归记录的数组中有遍历所有和差值,为了能用数组下标表示,把-100-100转化到0-200,计算一个数的和差值时加上100,这样虽然和差值变了,但对应和差值的数是没有变的。3.需要同时更新满足和差值的所有数的和以及个数,之所以要记录个数,是为了加上最高位对应的值,比如首位为1长度为5的情况,它的数之和为所有对应满足的长度为4的数之和加上 个数*10000.4.在最高位确定情况下,它的子问题(即位数少一位)的首位数是可以为零的。

具体看代码及注释:

 1 #include <cstdio>
 2 #define LIMIT 1000000007
 3
 4 long long dp[22][10][220][2] = {}; //分别表示数字的长度,数字首位数,和差的值+100,满足和差值的所有数的和以及个数
 5 long long basics[22] = {0, 1};  //预处理的数组,方便使用,分别为0,1,10,100,。。。
 6 long long lower, upper, sum; //三个输入的值
 7
 8 long long GetResult(long long number){
 9     int len = 0;
10     for(long long i = number; i; i /= 10, ++len);
11     long long result = 0;
12     for(int i = 1; i < len; ++i) //位数小于len的情况,首位数不能为零
13         for(int j = 1; j < 10; ++j)
14             result = (result + dp[i][j][sum + 100][0]) % LIMIT;
15     long long num = 0;
16     // 下面这个比较复杂,比如3333这个数,首先对于首位小于3长度为4的情况,直接加上dp中的值(此时num为0)
17     // 但是对于3则不行,因为不包含所有子情况,所以单独处理,也就是数字为333的情况的和加上 个数*3000(此时num为3)
18     //对于333也是一样,达到3的时候处理33加上(3300 *个数)
19     for(int i = len, tmp_sum = sum + 100, j; i > 0;
20          number -= basics[i] * j, --i, tmp_sum = 200 - (tmp_sum - j), num = num * 10 + j){
21         for(j = 0; basics[i] * (j+1) <= number; ++j){
22             if (i == len && j == 0)  //排除长度为len时首位为0,长度小于len首位可以为0
23                 continue;
24             result += dp[i][j][tmp_sum][0] + dp[i][j][tmp_sum][1] * (num * basics[i+1] % LIMIT) % LIMIT;
25         }
26         result %= LIMIT;
27     }
28     return result;
29 }
30
31 int main(){
32     for(int i = 2; i < 22; ++i)
33         basics[i] = basics[i-1] * 10;
34     scanf("%lld%lld%lld", &lower, &upper, &sum);
35     for(int i = 0; i < 10; ++i){ // 长度为一时的处理
36         dp[1][i][i+100][0] = i;
37         dp[1][i][i+100][1] = 1;
38     }
39     for(int i = 2; i < 22; ++i)
40         for(int j = 0; j < 10; ++j)
41             for(int k = 0; k < 200; ++k){
42                 for(int m = 0; m < 10; ++m){
43                     dp[i][j][k][0] += dp[i-1][m][200 - (k - j)][0]; //首位数为j,和差为k对应的长度为i-1的和差为200-(k-j)
44                     dp[i][j][k][1] += dp[i-1][m][200 - (k - j)][1]; //遍历所有子问题并更新
45                 }
46                 dp[i][j][k][0] += dp[i][j][k][1] * (j * basics[i] % LIMIT) % LIMIT; //加上最高位的对应值
47                 dp[i][j][k][0] %= LIMIT;
48                 dp[i][j][k][1] %= LIMIT;
49             }
50     long long result_upper = GetResult(upper+1);
51     long long result_lower = GetResult(lower);
52     long long result = result_upper - result_lower;
53     if(result < 0)
54         result += LIMIT;
55     printf("%lld\n", result);
56 }

 
时间: 2024-10-13 07:26:28

【上海交大oj】数学题3(数位dp)的相关文章

Timus OJ 1057 数位dp

http://acm.timus.ru/problem.aspx?space=1&num=1057 1057. Amount of Degrees Time limit: 1.0 second Memory limit: 64 MB Create a code to determine the amount of integers, lying in the set [X;Y] and being a sum of exactlyK different integer degrees of B.

Light OJ 1032 - Fast Bit Calculations(数位DP)

题目大意: 一个数字把他看成二进制数字,数字里又会一些相邻的1,问从0到n至间所有相邻1的总和是多少? 分解成2进制数字,然后数位DP就行了. ======================================================================== #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<

swust oj 1097--2014(数位dp)

题目链接:http://acm.swust.edu.cn/problem/1097/ Time limit(ms): 1000 Memory limit(kb): 32768 今年是2014年,所以小明喜欢2014的每一位数字(即:2,0,1,4),小明想知道在区间[l,r](包括l和r)中有多少个数中含有这4个数字(数字无前缀零). Description 多组数据. 每组数据输入2个数l,r(0<l<r<=10^9) Input 输出占一行,即区间[l,r](包括l和r)中包含的满足

swust oj 648--简单字典(数位dp)

题目链接:http://acm.swust.edu.cn/problem/0648/ Time limit(ms): 1000 Memory limit(kb): 65535 有这样一本字典,它每个单词一页,单词没有相同字母. 就像这样: a 1 b 2 . . z 26 ab 27 . . az 51 ba 52 bc 53 . . Description 多组测试数据,每行是一个串长最大为10由小写字母组成的单词. 以EOF结束. Input 输出这个单词在这本字典的第几页 Output 1

BZOJ 3209: 花神的数论题【数位dp】

Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了.花神的题目是这样的设 sum(i) 表示 i 的二进制表示中 1 的个数.给出一个正整数 N ,花神要问你派(Sum(i)),也就是 sum(1)—sum(N) 的乘积. Input 一个正整数 N. Output 一个数,答案模 10000007 的值. Sample Input 样例输入一3 S

FZU 2113 BCD Code 数位dp

数位dp,但是很奇怪的是我在虚拟oj上用GUC C++提交会wa,用Visual c++提交正确,但是加上注释后提交又莫名CE……好任性啊 0 ,0 题目思路:看代码吧 注释很详细 #include<iostream>#include<algorithm>#include<cstring>#include<vector>#include<stdio.h>#include<stdlib.h>#include<queue>#i

zznu 1255 数字统计(数位DP, 数学方法)

最近在学数位DP, 感觉还是满有收获的! 做了几个题之后想起来自己OJ上曾经做的一道题,以前是用数学方法写的,现在改用数位DP来写了一遍. 题目: 1255: 数字统计 时间限制: 1 Sec  内存限制: 128 MB提交: 31  解决: 4[提交][状态] 题目描述 一本书的页码从自然数1 开始顺序编码直到自然数n.书的页码按照通常的习惯编排, 每个页码都不含多余的前导数字0.例如,第6 页用数字6 表示,而不是06 或006 等.数 字计数问题要求对给定书的总页码n,计算出书的全部页码中

【HDU 4352】 XHXJ&#39;s LIS (数位DP+状态压缩+LIS)

XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2422    Accepted Submission(s): 990 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then careful

bzoj 3209: 花神的数论题 数位dp

3209: 花神的数论题 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了.花神的题目是这样的设 sum(i) 表示 i 的二进制表示中 1 的个数.给出一个正整数 N ,花神要问你派(Sum(i)),也就是 sum(