数位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思路:
以上这种做法对于这道题有点取巧,而真正的数位DP的模板应该如下:
然后进阶做一下对应的拓展练习:数字0-9的数量
虽然对于数位DP还是存在
e2c7
一些疑惑,但是基本上搞懂了这下,不过下面那道幸运区间感觉真的不怎么友好
如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
一些疑惑,但是基本上搞懂了这下,不过下面那道幸运区间感觉真的不怎么友好
相关文章推荐
- 【51nod 1009】数字1的数量 【数位DP 模板】
- 51Nod 数字0到9的数量 (数位DP)
- 51nod 1042 数字0-9的数量(数位dp)
- 51nod 1042 数字0-9的数量 数位DP
- 51nod 1009 数字1的数量(数位dp)
- 【51Nod】1042 - 数字0-9的数量(数位dp & 递归)
- 51nod 1042 数字0-9的数量 数位dp
- 51nod:数字1的数量(线性dp or 数位dp)
- 51nod数字0-9的数量(数位dp)
- 51Nod 1042 数字0-9的数量 (数位DP
- 51Nod 1042 数字0-9的数量 (数位DP
- 51nod 1042 数字0-9的数量 数位DP
- 51Nod 1009 数字1的数量(数位dp)
- 51nod 1009 数字1的数量【数位dp】
- 51nod 1042 数字0-9的数量(数位dp)
- 51nod 1042 数字0-9的数量(数位DP)
- 【数位dp入门】51nod 1009 数字1的数量
- 51nod 数字1的数量(数位DP)
- 51nod 1009 数字1的数量 数位dp
- 51nod 1009 数字1的数量(数位dp)