51nod 1042 数位dp
2017-08-21 10:18
260 查看
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1042
基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 收藏 关注 给出一段区间a-b,统计这个区间内0-9出现的次数。 比如 10-19,1出现11次(10,11,12,13,14,15,16,17,18,19,其中11包括2个1),其余数字各出现1次。 Input两个数a,b(1 <= a <= b <= 10^18)Output
输出共10行,分别是0-9出现的次数Input示例
10 19Output示例
1 11 1 1 1 1 1 1 1 1i
经典的数位dp题目,但是这个'0'真是搞得我恶心,第一次见是在玲珑某次比赛,那次一直怼这个最后爆零- -
dp[i]表示[0,10
-1]之间所有的数里面0-9出现的次数,有dp[i]=10*dp[i-1]+pow(10,i-1),显然1-9的次数的一样的,0得话,
因为没有以零开头的多位数,所以这里面是多计算了一部分'0'的,计算时遇到0就要想办法减去他才行。
假如[0,999],多计算的就是100+10+1个零,对应的是001,002.....099,100是最高位,10是次高位,依次递推。
假如要计算f(2049,0),第一次 s+=dp[3]*2;
这两个dp[3]一个是加的 [0,999]一个是[1000,1999],但是我们只去掉一次就好了因为在[1000,1999]间那些零反而是我们需要的,就是这一点我糊涂好久。
#include<cstring> #include<iostream> #include<cstdio> #include<cmath> using namespace std; #define inf 0x3f3f3f3f #define LL long long LL dp[25], zero[25] = { 0,0,10 }; LL qpow(LL a,LL b,LL r=1){for(;b;b>>=1,a=a*a)if(b&1)r=r*a;return r;} void init() { dp[1]=1; for(LL i=2;i<19;++i) dp[i]=10*dp[i-1]+qpow(10,i-1); } LL f(LL N,LL digit) { if(N==0) {return digit?0:1;} int len=log(N+0.05)/log(10)+1; LL s=0,nx=N; for(int i=len;i>=1;--i) { LL mul=qpow(10,i-1); s+=dp[i-1]*(N/mul); { if(N/mul-1>=digit) s+=qpow(10,i-1); if(N/mul==digit) s+=N%mul+1; } N%=mul; //if(!digit) cout << "s=" << s << endl; } if (!digit) // 删除前缀是0的结果 { LL m = 1; while (nx) { s -= m; m *= 10; nx = nx / 10; } } //if (!digit) cout <<"s="<< s << endl; return s; } int main() { init(); LL a,b,x; cin >> a >> b; for(x=0;x<=9;++x) { cout<<f(b,x)-f(a-1,x)<<endl; } return 0; }
这是从新学习后自己写的代码
#include<bits/stdc++.h> using namespace std; #define LL long long LL f[25]={0,1}; LL p10[25]={1,1}; LL zero[25]={0,0}; LL bit[25]; void init(){ for(int i=1;i<=20;++i) p10[i]=p10[i-1]*10; for(int i=2;i<=20;++i) zero[i]=zero[i-1]*10+10; for(int i=2;i<=20;++i) f[i]=f[i-1]*10+p10[i-1]; } LL cal(LL N,int x){ int len=0; while(N){ bit[len++]=N%10; N/=10; } bit[len]=-1; LL ans=0,tot=0; for(int i=len-1;i>=0;--i){ ans+=f[i]*bit[i]; if(!x && i==len-1) ans-=(LL)(zero[i]); if(bit[i]>x && ((x==0&&i==len-1)==0) ) ans+=p10[i]; ans+=p10[i]*bit[i]*tot; if(bit[i]==x) tot++; } return ans; } int main(){ LL l,r,n,i,j,k; init(); while(scanf("%lld%lld",&l,&r)==2){ for(i=0;i<10;++i) printf("%lld\n",cal(r+1,i)-cal(l,i)); } return 0; }
相关文章推荐
- 51Nod 1042 数字0-9的数量 (数位DP
- 51nod 1042 数字0-9的数量【数位dp】
- 51Nod 1042 数字0-9的数量 (数位DP
- 51Nod 1009 1042 数位DP
- 51nod 1042 数字0-9的数量 数位dp
- 51nod 1042 数字0-9的数量(数位DP)
- 51Nod - 1042 数位dp
- 51nod 1042 数字0-9的数量(数位dp)
- 【51Nod】1042 - 数字0-9的数量(数位dp & 递归)
- 51nod 1042 数字0-9的数量 数位DP
- 51nod 1042 数字0-9的数量 数位DP
- 51nod 1042 数字0-9的数量(数位dp)
- 51nod 1043 幸运数字(数位dp)
- 51nod 1009 数字1的数量【数位dp】
- 51nod 1569 二项式系数的个数 kummer定理+数位dp
- 51Nod 数字0到9的数量 (数位DP)
- 【数位dp入门】51nod 1009 数字1的数量
- 51nod 1009 数字1的数量(数位dp)
- 51nod 1043 幸运号码 (数位dp)
- 1042 数字0-9的数量(数位DP)