您的位置:首页 > 其它

数位dp 总结 51nod数字1的数量 数字0-9的数量

2017-11-10 01:26 393 查看
这是一道数位dp题,以前没见过,看了一下别人的想法,终于明白了。

如12可以分为f(9)(1-9的1的个数)+f(2)(1-2的1的个数) +最高位出现1的个数。不过值得注意的是这里最高位是否为1需要判断,决定了其前一位的重复个数,以及最高位的个数。

详细看下:



接着就传统的dp思路:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int n;
char s[10];

int f(int n){///每次获取首位元素
if(n==0)
return 0;
else if(1<=n&&n<=9)
return 1;
sprintf(s,"%d",n);
int bg=s[0]-'0';
int dig=0;
for(int i=0;s[i]!='\0';i++)
dig++;
if(bg==1){
return f(pow(10,dig-1)-1)+f(n-pow(10,dig-1))+n-pow(10,dig-1)+1;
}
else
return bg*f(pow(10,dig-1)-1)+f(n-bg*pow(10,dig-1))+pow(10,dig-1);
}

int main(){
while(scanf("%d",&n)!=EOF){
printf("%d\n",f(n));
}
return 0;
}


以上这种做法对于这道题有点取巧,而真正的数位DP的模板应该如下:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int c[10];
int n;

void dp(int n,int d){//n为当前数字,d为当前最低位所代表的进位(如个位对应进位为1,十位进位为10...
int h=n/10,l=n%10,temp=h;//h代表的是除去当前数字的最低位所剩下的高位,l则是当前数字的最低位
for(int i=0;i<=l;i++)
{c[i]+=d;/*cout<<"c:"<<c[i]<<endl;*/}//把最低位出现的数字先记录下来,要对应进位,因为如果最低位是个位,则每一个数字的出现只对应一位,而如果是十位,每个数字的出现就对应有10个(如,10,11,12...19)
for(int i=0;i<=9;i++) c[i]+=d*h;//再计算对应低位每个数字之前出现的次数
c[0]-=d;//0这个地方多算了要减去因为像00 01这样的数是不存在的
while(temp){
c[temp%10]+=(l+1)*d;///再计算当前数字较高位对应出现的次数如23 对应20 21 23 2出现了三次
temp/=10;///不断地往较高位走
}
if(h)///递归出口
dp(h-1,d*10);///计算高位的前一个数 比如23 此时就是计算1开头的情况
}

int main(){
while(scanf("%d",&n)!=EOF){
memset(c,0,sizeof(c));
dp(n,1);
printf("%d\n",c[1]);
}
return 0;
}

然后进阶做一下对应的拓展练习:数字0-9的数量

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e8+50;
long long a[10],b[10];
long long l,r;

void dp(long long t,long long *c,long long d){
long long n=t/10,m=t%10;//n=1,m=9
long long temp=n;//temp=1
for(int i=0;i<=m;i++)
c[i]+=d;
for(int j=0;j<=9;j++)
c[j]+=d*n;
c[0]-=d;
while(temp){
c[temp%10]+=(m+1)*d;
temp/=10;
}
if(n)
dp(n-1,c,d*10);
}

int main(){
while(scanf("%lld%lld",&l,&r)!=EOF){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
dp(l-1,a,1);
dp(r,b,1);
for(int i=0;i<=9;i++)
printf("%lld\n",b[i]-a[i]);
}
return 0;
}


虽然对于数位DP还是存在
e2c7
一些疑惑,但是基本上搞懂了这下,不过下面那道幸运区间感觉真的不怎么友好
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: