[bzoj1833][DP]count 数字计数
来源:互联网 发布:淘宝上美瞳为什么便宜 编辑:程序博客网 时间:2024/06/01 19:28
Description
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
Input
输入文件中仅包含一行两个整数a、b,含义如上所述。
Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。
Sample Input
1 99
Sample Output
9 20 20 20 20 20 20 20 20 20
HINT
30%的数据中,a<=b<=10^6; 100%的数据中,a<=b<=10^12。
题解
真的是痛苦。。这题折磨了我
三天
一开始想的是二维预处理+区间缩小。结果我发现二维的在缩小的情况下是无法转移的。。怎么办?一分钟后我发现可以换成三维
设num[i][j][k]为 位数为i的数字,以j开头中第k种数字有多少个
先想如何预处理吧。首先,每个num[i][j][j]肯定要赋值为10^(i-1)对吧。因为i-1位到i位中,肯定至少有10^(i-1)个数字是以j开头的。
预处理完后我们枚举i-1位。因为i位数字实际上就是i-1位这些数字+任意一个数字组合而来的。譬如34567这个五位数 实际上就是3+4567这个四位数组成的嘛。那么i-1位的结果肯定对于i是有用的。枚举i位数开头数字j,i-1位数开头数字k,继承状态l
num[i][j][l]+=num[i-1][k][l]
好了我们预处理完了。那么询问的区间很明显是可以用大区间减去小区间对吧。
做一遍0~r再做一遍0~l-1最后输出就行了
怎么计算?首先对于位数<边界数位数 的数字,我们直接加就好了
譬如23005,我们把1~4位数的结果当然全部都要先加起来嘛。然后再处理其他的
对于位数等于边界数位数的数。我们就要一点一点加了
还是上面这个23005的例子。我们已经预处理过num[5][1][k]了对吧。而且10000~19999这些数一定可以被加起来。那么就直接加咯
那20000~23005怎么办??观察一下。可以拆成四位数的方法0~3005对不对?只要加上以2开头的五位数的个数就好了啊
那么这样一层一层叠下去。。就ok了
#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>using namespace std;typedef long long LL;LL num[15][15][15];//i位 最高位为j 第k个数字出现次数 int s[15];int Get(LL u){ int ret=0; while(u) { s[++ret]=u%10; u/=10; } return ret;}LL pow(int u){ LL ret=1,a=10; while(u!=0) { if(u%2==1)ret=ret*a; a=a*a;u/=2; } return ret;}LL ans[15][2];void sol(LL u,int op){ if(u<0)return ; int len=Get(u);LL tmp=u; if(u!=0)ans[0][op]++; for(int i=1;i<len;i++) for(int j=1;j<=9;j++) for(int k=0;k<=9;k++)ans[k][op]+=num[i][j][k]; for(int i=1;i<s[len];i++) for(int k=0;k<=9;k++)ans[k][op]+=num[len][i][k]; ans[s[len]][op]+=tmp-(s[len]*pow(len-1))+1; tmp-=(s[len]*pow(len-1)); for(int i=len-1;i>=1;i--) { for(int j=0;j<s[i];j++) for(int k=0;k<=9;k++)ans[k][op]+=num[i][j][k]; ans[s[i]][op]+=tmp-(s[i]*pow(i-1))+1; tmp-=(s[i]*pow(i-1)); }}int main(){ LL a,b; scanf("%lld%lld",&a,&b); int lenx=Get(a),leny=Get(b); for(int i=1;i<=12;i++) for(int j=0;j<=9;j++) { num[i][j][j]=pow(i-1); for(int k=0;k<=9;k++) for(int l=0;l<=9;l++) num[i][j][k]+=num[i-1][l][k]; } sol(b,0); sol(a-1,1); for(int i=0;i<9;i++)printf("%lld ",ans[i][0]-ans[i][1]); printf("%lld\n",ans[9][0]-ans[9][1]); return 0;}
- [bzoj1833][DP]count 数字计数
- bzoj1833: [ZJOI2010]count 数字计数 数位dp
- [BZOJ1833] [ZJOI2010]count 数字计数 && 数位DP
- 【bzoj1833】[ZJOI2010]count 数字计数 数位DP
- Bzoj1833:[ZJOI2010]count 数字计数:数位dp
- 【BZOJ1833】【数位DP】 count 数字计数
- bzoj1833[ZJOI2010]count 数字计数 数位DP
- bzoj1833 count 数字计数
- BZOJ1833[count 数字计数]
- BZOJ1833: [ZJOI2010]count 数字计数
- [BZOJ1833][ZJOI2010]count数字计数
- [BZOJ1833] [ZJOI2010]count 数字计数
- BZOJ1833 [ZJOI2010]count 数字计数
- BZOJ1833: [ZJOI2010]count 数字计数
- bzoj1833: [ZJOI2010]count 数字计数
- BZOJ1833: [ZJOI2010]count 数字计数
- bzoj1833: [ZJOI2010]count 数字计数
- BZOJ1833 [ZJOI2010]count 数字计数
- excel拼接换行符:char(10)
- 25-IP Address Allocation I
- 日期与时间
- 机器学习——监督学习(一)
- ubuntu下启动AS 模拟器报错" Unknown AVD name "
- [bzoj1833][DP]count 数字计数
- PTA-根据后序和中序遍历输出先序遍历
- 26-LTE IP Address Allocation II
- MvpRtrofit
- arc_web_tips
- matlab基础
- 笔试、面试题收集(主要是Python Web开发)
- 常用的排序算法
- 虾米音乐代码注释惊现 “穷逼 vip”,程序员要出来接锅了