写在前面

这两天信息量有点大,需要好好消化一下,呼呼

\(f[i][j]\) 的转移式还是好理解的,但是对于其实际意义课上有点糊

求 \(ans_{1, x}\) 是感觉手动把数拆开看会好理解一点??

同级某巨佬wxf会用记忆化搜索做,我不会,太菜了


luoguP4999 烦人的数学作业

简述题意:

给定区间 \([ L , R ]\) ,求 \(L\) 到 \(R\) 区间内每个数字和 $ (1 \le L \le R \le 10^{18}) $ ,共 \(T\) 组数据 \((1 \le T \le 20)\)

Solution:

数位DP入门题?

设 \(f[i][j]\) ,第一维表示枚举到第 \(i\) 位, 第二维表示以 \(j\) 为最高位, \(f\) 数组用来存数字和

如 \(f[i][j]\) 中存的是 \([j000\cdots \ , \ j999\cdots]\) 这一区间的数字和,(其中每个数都有 \(i\) 位)

初始状态: \(f[1][i] = i \ (0 \le i \le 9)\)

考虑怎么转移,新枚举到的 \(f[i][j]\) 是在 \(f[i -1][k]\) 基础上加上新的一位,而因为新的一位后面可以跟 \(0 - 9\) 所有数,所以 \(k\) 的取值是 \(0 - 9\) , 因为这样的数的数量是 \(10^{i - 1}\) 个,所以转移方程就推出来啦:

\[f[i][j] = ( \sum_{k = 0}^{9} f[i - 1][k] ) + j \times 10^{i - 1}
\]

考虑最后怎么合并答案 \(ans_{l, r}\) ,

可以考虑先求出 \(ans_{1, l}\) 和 \(ans_{1, r + 1}\) 的答案,最后在进行合并(至于为什么是 \(l\) 和 \(r + 1\) 后面会进行解释

手模一个样例看看: \(ans_{1, 114514}\)

发现可以将它拆开:

\[\begin{aligned}
& 114514 = \{ 0 - 99999 \} + \{ 100000 - 109999\} \\
& + \{ 110000 - 110999 ,111000 - 111999 , 112000 - 112999 , 113000 - 113999 \} \\
&+ \cdots \\
\end{aligned}
\]

用 \(f[i][j]\) 数组一个一个代换即可,前面多出的数可以用 \(sum\) 存一下在循环最后处理

在每一层后面处理一下前面多出的数(感觉说不清楚,感性理解一下/kk

可以发现循环到最后一位时并不会加上最后一个数,所以将所求区间整理一下就好啦

LL solve(LL x){
LL ans = 0, sum = 0;
LL s[22], len = 0;
for(;x; x /= 10) s[++len] = x % 10; for(int i = len; i >= 1; --i){
for(int j = 0; j < s[i]; ++j){
ans = (ans + f[i][j]) % mod;
}
ans = (ans + sum * s[i] * quick_pow(10, i - 1) % mod) % mod;
sum = (sum + s[i]) % mod;
}
return ans;
}

(一开始感觉这样写比 \(Aliemo\)写的简单,后来发现并没有什么本质的区别)

code:

/*
Work by: Suzt_ilymics
Knowledge: 数位DP
Time: luogu最优解第五?
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long using namespace std;
const int mod = 1e9+7; LL read(){
LL s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
return s * w;
} LL T, l, r, ans = 0;
LL f[22][22]; LL quick_pow(LL x, LL p){//快速幂
LL res = 1;
for( ; p; p >>= 1){
if(p & 1) res = res * x;
x = x * x;
}
return res;
} void init(){//初始化
for(int i = 1; i <= 9; ++i) f[1][i] = i; for(int i = 2; i <= 19; ++i){
for(int j = 0; j <= 9; ++j){
for(int k = 0; k <= 9; ++k){
f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
}
f[i][j] = (f[i][j] + j * quick_pow(10, i - 1)) % mod;
// cout<<f[i][j]<<" ";
}
// cout<<"\n";
}
} LL solve(LL x){//求ans(1 - x)
LL ans = 0, sum = 0;
LL s[22], len = 0;
for(;x; x /= 10) s[++len] = x % 10; for(int i = len; i >= 1; --i){
for(int j = 0; j < s[i]; ++j){
ans = (ans + f[i][j]) % mod;
}
ans = (ans + sum * s[i] * quick_pow(10, i - 1) % mod) % mod;
sum = (sum + s[i]) % mod;
}
return ans;
} signed main()
{
init();
T = read();
while(T--){
l = read(), r = read();
printf("%lld\n", (solve(r + 1) - solve(l) + mod) % mod);
}
return 0;
}
/*
in:
2 1 1000000000000000000 1 1000000000000000000 out:
3970 3970 */

luoguP4999 烦人的数学作业的更多相关文章

  1. P2602 [ZJOI2010]数字计数&P1239 计数器&P4999 烦人的数学作业

    P2602 [ZJOI2010]数字计数 题解 DFS 恶心的数位DP 对于这道题,我们可以一个数字一个数字的求 也就是分别统计区间 [ L , R ] 内部数字 i 出现的次数 (0<=i&l ...

  2. [洛谷P4999]烦人的数学作业

    题目大意:定义$f(x)$表示$x$每一个数位(十进制)的数之和,求$\sum\limits_{i=l}^rf(i)$,多组询问. 题解:数位$DP$,可以求出每个数字的出现个数,再乘上每个数字的大小 ...

  3. 题解 P4999 【烦人的数学作业】

    数位 dp. 设 \(dp_{q,i}\)(\(i\in\{0,1,2,3,4,5,6,7,8,9\}\))为 \(1\sim q\) 中 \(i\) 出现的次数,\(1\sim q\) 的数字和显然 ...

  4. 得物(毒)APP,8位抽奖码需求,这不就是产品给我留的数学作业!

    作者:小傅哥 博客:https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki 沉淀.分享.成长,让自己和他人都能有 ...

  5. BZOJ-2326 数学作业 矩阵乘法快速幂+快速乘

    2326: [HNOI2011]数学作业 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1564 Solved: 910 [Submit][Statu ...

  6. sdibt 1244 烦人的幻灯片

    在这个OJ站还没号,暂时没提交,只是过了样例 真不愧是烦人的幻灯片,烦了我一小时 ---更新:OJ测试完毕,AC 烦人的幻灯片问题 Time Limit: 1 Sec  Memory Limit: 6 ...

  7. bzoj2326: [HNOI2011]数学作业

    矩阵快速幂,分1-9,10-99...看黄学长的代码理解...然而他直接把答案保存在最后一行(没有说明...好吧应该是我智障这都不知道... #include<cstdio> #inclu ...

  8. BZOJ 2326: [HNOI2011]数学作业( 矩阵快速幂 )

    BZOJ先剧透了是矩阵乘法...这道题显然可以f(x) = f(x-1)*10t+x ,其中t表示x有多少位. 这个递推式可以变成这样的矩阵...(不会用公式编辑器...), 我们把位数相同的一起处理 ...

  9. iOS 界面 之 EALayout 无需反复编译,可视化实时界面,告别Storyboard AutoLayout Xib等等烦人的工具

    http://blog.csdn.net/fatherhui iOS开发,EALayout 无需反复编译,可视化实时界面,告别Storyboard AutoLayout Xib等等烦人的工具 EALa ...

随机推荐

  1. Win10环境安装node.js和npm

    Node.js和npm的关系 Node.js是一个基于Chrome V8引擎的JavaScript运行环境,使用了事件驱动非阻塞式I/O模型. npm(Node Package Manager)是一个 ...

  2. easyui中权限分配和添加 前后端代码

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  3. Java动态代理分析

    Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地制定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分配到委托对象上反射执行,配置执行过程中,开发 ...

  4. [LeetCode]86. Partition List分离链表

    /* 这个题是medium的意思应该是用双指针的方法做,如果使用下边的新建链表的方法,就是easy的题目了 双指针会用到很多链表的相连操作 */ public ListNode partition(L ...

  5. [leetcode]114. Flatten Binary Tree to Linked List由二叉树构建链表

    /* 先序遍历构建链表,重新构建树 */ LinkedList<Integer> list = new LinkedList<>(); public void flatten( ...

  6. 分布式ID生成策略之ZK

    import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFra ...

  7. 企业集群架构-03-NFS

    NFS 目录 NFS NFS基本概述 NFS应用场景 NFS实现原理 NFS总结 NFS服务端安装 环境准备 服务端安装NFS 服务端NFS配置 服务端开机自启 服务端验证配置 NFS客户端挂载卸载 ...

  8. 为什么Java中lambda表达式不能改变外部变量的值,也不能定义自己的同名的本地变量呢?

    作者:blindpirate链接:https://www.zhihu.com/question/361639494/answer/948286842来源:知乎著作权归作者所有.商业转载请联系作者获得授 ...

  9. ES6 对象拓展方法

    一,ES6 对象拓展方法 ES6为对象提供了一些拓展方法,下面列举几个比较常见的对象拓展方法.

  10. hive行转列,列转行

    实例一:来源: https://www.cnblogs.com/kimbo/p/6208973.html 行转列 (对某列拆分,一列拆多行) 使用函数:lateral view explode(spl ...