数位DP 求K进制下0~N的每个数每位上出现的数的总和
好久没写博客了,因为感觉时间比较紧,另一方面没有心思,做的题目比较浅也是另一方面。
热身赛第二场被血虐了好不好,于是决定看看数位DP吧。
进入正题:
如题是一道经(简)典(单)的数位dp。
第一步,对于数K^n-1这种形式的数,位数为n,它的各个位上,每个数0~K-1出现过的次数是一样的。
于是对于数B=K^n-1,有f(B)=(B+1)*n*(0+1+2+...+K-1)/K=(B+1)*n*(K-1)/2;
程序为:
LL sum1(int pre,int n,int k)
{
LL ret=;
LL pw=;
for(int i=;i<n;i++) pw*=k;
ret=pre*pw+pw*n*(k-)/;
return ret;
}
其中pre在这种情况下为0,pre是什么?我们立刻进入下一步讨论。
第二步,由第一步的结论,我们可以引申一下。为了更形象一点,我们不妨在十进制的情况下讨论。
现在我提出一个问题:如何计算0~49999的数它们各个位上数字之和?(K=10的前提下)
我们根据第一步可以很容易求出[0,9999]=(9999+1)*4*(10-1)/2。
那么还剩下[10000,19999],[20000,29999],[30000,39999],[40000,49999]该怎么求?
仔细观察发现[10000,19999]不过是每个数都比[0,9999]多了一个为1的万位,[20000,29999]不过是每个数都比[0,9999]多了一个为2的万位,[30000,39999]不过是每个数都比[0,9999]多了一个为3的万位,依次类推...就发现了规律。
所以此时这个与后面的数位都无关的万位,我们用i表示,万位之前没有其他的位,所以pre=0(如果对pre有点不理解,看完第三步就知道了),于是对于[i0000,i9999]这样的解就是((pre+i)*10000)+(9999+1)*4*(10-1)/2。
那么,不难得知,求解通式即为((pre+i)*K^n)+(K^n)*n*(K-1)/2。
第三步,基于第一步和第二步的结论,已经可以求出类似于999(K=10),39999(K=10),49999(K=10)的解。
现在又提出一个问题,对于[0,54321]我们怎么解?
当然,先延续之前“区间划分”+“前缀”的思路,先划分为[0,9999],[10000,19999],[20000,29999],[30000,39999],[40000,49999],[50000,54321]。
对于[0,9999],[10000,19999],[20000,29999],[30000,39999],[40000,49999]已经讨论过了,接下来讨论如何求[50000,54321]。
这时把万位的5看作一个前缀,区间就变为了[0,4321],于是只要求前缀pre=5的[0,4321]的解,也就是递归调用第二步的方法,这样就可以求到[0,321],[0,21],[0,1]这样把所有的解相加,就是需要的答案了。
LL sum2(int pre,LL n,int k)
{
if(n<k){
LL ret=;
for(int i=;i<=n;i++) ret+=pre+i;
return ret;
}
LL tn=n,pw=,ret=;
int mi=;
while(tn>=k){
pw*=k;
mi++;
tn/=k;
}
for(int i=;i<tn;i++)
ret+=sum1(pre+i,mi,k);
ret+=sum2(pre+tn,n-tn*pw,k);
return ret;
}
为了验证跑出来的数据对不对,再写一个暴力求[0,n]的程序,这查错的办法。
LL check(int n,int k)
{
LL ret=;
int t;
for(int i=;i<=n;i++){
t=i;
while(t){
ret+=t%k;
t/=k;
}
}
return ret;
}
完整程序:
#include <stdio.h>
typedef long long LL; LL sum1(int pre,int n,int k)
{
LL ret=;
LL pw=;
for(int i=;i<n;i++) pw*=k;
ret=pre*pw+pw*n*(k-)/;
return ret;
} LL check(int n,int k)
{
LL ret=;
int t;
for(int i=;i<=n;i++){
t=i;
while(t){
ret+=t%k;
t/=k;
}
}
return ret;
} LL sum2(int pre,LL n,int k)
{
if(n<k){
LL ret=;
for(int i=;i<=n;i++) ret+=pre+i;
return ret;
}
LL tn=n,pw=,ret=;
int mi=;
while(tn>=k){
pw*=k;
mi++;
tn/=k;
}
for(int i=;i<tn;i++)
ret+=sum1(pre+i,mi,k);
ret+=sum2(pre+tn,n-tn*pw,k);
return ret;
} int main()
{
LL n;
int k;
while(~scanf("%I64d %d",&n,&k)){
printf("%I64d\n",sum2(,n,k));
printf("%I64d\n",check(n,k));
}
return ;
}
数位DP 求K进制下0~N的每个数每位上出现的数的总和的更多相关文章
- n!在k进制下的后缀0
问n! 转化成k进制后的位数和尾数的0的个数.[UVA 10061 How many zeros and how many digits?] Given a decimal integer numbe ...
- 求x!在k进制下后缀零的个数(洛谷月赛T1)
求x!在k进制下后缀和的个数 20分: 求十进制下的x!后缀和的个数 40分: 高精求阶乘,直接模拟过程 (我不管反正我不打,本蒟蒻最讨厌高精了) 60分 利用一个定理(网上有求x!在 ...
- bzoj 3000 Big Number 估算n!在k进制下的位数 斯特林公式
题目大意 求n!在k进制下的位数 2≤N≤2^31, 2≤K≤200 分析 作为数学没学好的傻嗨,我们先回顾一下log函数 \(\log_a(b)=\frac 1 {log_b(a)}\) \(\lo ...
- 51 Nod 1116 K进制下的大数
1116 K进制下的大数 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 关注 有一个字符串S,记录了一个大数,但不知这个大数是多少进制的,只知道这个数 ...
- PAT 1015 Reversible Primes[求d进制下的逆][简单]
1015 Reversible Primes (20)(20 分)提问 A reversible prime in any number system is a prime whose "r ...
- 陕西师范大学第七届程序设计竞赛网络同步赛 F WWX的礼物【数学/k进制下x^n的位数/log】
链接:https://www.nowcoder.com/acm/contest/121/F来源:牛客网 题目描述 WWX的女朋友送给了他一个礼物,可是礼物却被一把K进制密码锁锁住了.在礼物盒上还有一张 ...
- [51nod1116]K进制下的大数
解题关键:$A\% (k - 1) = (A[0] + A[1]*k + A[2]*{k^2} + ...A[n]*{k^n})\% (k - 1) = (A[0] + A[1] + ...A[n]) ...
- 51nod 1116 K进制下的大数
你万万想不到,Long Long 就能存下的数据 #include <iostream> #include <cstdio> #include <cstdlib> ...
- A - K进制下的大数
https://vjudge.net/contest/218366#problem/A 中间溢出,注意求模. #include<iostream> #include<cstdio&g ...
随机推荐
- 理解CSS3 transform中的Matrix(矩阵)
一.哥,我被你吓住了 打架的时候会被块头大的吓住,学习的时候会被奇怪名字吓住(如“拉普拉斯不等式”).这与情感化设计本质一致:界面设计好会让人觉得这个软件好用! 所以,当看到上面“Matrix(矩阵) ...
- hdu 小希的迷宫
真是被这道并查集的水题给坑哭了...忘记给uset数组初始化我也是醉了. 题目意思是找到判断是不是连通无环的图,首先想到的就是并查集. 1判断成环的时候,只要判断输入边的两个点.有一个共同的父节点,那 ...
- unity3d插件Daikon Forge GUI 中文教程3-基础控件Button和Sprite的使用
2.2添加一个按钮Button 来看看特有的属性:Button Properties Data 显示的文本 Behavior 中的几个: Aoto Size 选中时就是按钮的背景会根据Data中的文本 ...
- daterangepicker 日期范围插件自定义 可选 年份
minDate:'01/01/2012',maxDate:'01/01/2015' $("#txtPODate").daterangepicker({ singleDatePick ...
- SQL 语句调用这个存储过程,生成顺序编码
一直很讨厌存储过程,没想到今天帮了我大忙啊,或许会因为今天让我慢慢喜欢上存储过程吧,不多说了,切入正题 在使用数据库的时候,难免要在使用过程中进行删除的操作,如果是使用int类型的字段,令其自增长,这 ...
- HTML DOM insertBefore() 方法 使用的时候发现一个问题,记录下
在W3C中是这样定义的 第二个参数是可先的,但是在谷歌浏览器和火狐浏览器中测试是会有bug的,第二个参数是必填的,否则会报错 感兴趣的可以测试 以下是我测试的结果: 谷歌浏览器:Uncaught ...
- BizTalk开发系列(三十一)配置和使用HTTP适配器
BizTalk的主机分别进程内主机和独立主机.但由于一直使用的是进程内主机,对于独立主机的认识比较模糊,前不久在做一个BizTalk的项目的时 候,个别系统使用HTTP的方式发布Txt之类的文本的.刚 ...
- C# Array
一.声明数组时,方括号[]必须跟在类型后面,而不是标识符后面 int[] table; //而不是 int table[]; 二.数组的大小不是其类型的一部分 int[] numbers; numb ...
- C# Image 、 byte[] 、Bitmap之间的转化
一.Byte[] 转 System.Drawing.Bitmap public static Bitmap CreateBitmap(byte[] originalImageData, int ori ...
- HDU 4358 Boring counting(莫队+DFS序+离散化)
Boring counting Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others) ...