【算法】数位DP

【题解】

记忆化搜索

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
ll A[],B[],f[][],a[],p[];
ll dfs(ll* A,ll h,bool limit,bool pre)
{
if(h==)return ;
if(!limit&&f[h][]!=-&&!pre)
{
for(int i=;i<=;i++)A[i]+=f[h][i];
return f[h][];
}
int end=limit?a[h]:;ll ans=;
for(int i=;i<=end;i++)
{
if(limit&&i==end)p[i]=dfs(A,h-,,pre&(!i)),A[i]+=p[i],ans+=p[i];
else p[i]=dfs(A,h-,,pre&(!i)),A[i]+=p[i],ans+=p[i];
if(pre&(!i))A[i]-=p[i];
}
if(!limit&&!pre)
{
for(int i=;i<=;i++)f[h][i]=f[h-][i]*+p[i];
f[h][]=ans;
}
return ans;
}
void solve(ll* A,ll x)
{
if(x==){return;}
int n=;
while(x>)a[++n]=x%,x/=;
dfs(A,n,,);
}
int main()
{
ll l,r;
scanf("%lld%lld",&l,&r);
for(int i=;i<=;i++)f[i][]=-;
solve(B,l-);solve(A,r);
for(int i=;i<;i++)printf("%lld ",A[i]-B[i]);
printf("%lld\n",A[]-B[]);
return ;
}

递推:下面只考虑单一数字数量统计,其它一样。

第一步,预处理。(计数)

规定最低位为第1位,最高位为第len位。

f[i][j]表示前i位,最高位数字为j的答案数(不考虑前导零有前导零的数字只要待会再最高位附上数字就是有效的了)

f[i][j]=∑f[i-1][k]+10^(i-1)。

第二步,第len位为0。(前导零)

将所有len位为0的或数字长度不足len的数字先统计进来,ans+=∑f[i][j]+1,1<=i<=len-1,1<=j<=9。其中+1是数字0。

第三步,第len位不为0逐位确定。(限位)

强制确定len位不为0,然后加入每一位枚举到顶-1的答案就可以了。

ans+=∑f[i][j],1<=i<len,0<=j<=a[i],其中i=len时j从1开始。

还要计算当前数位的顶之后会出现的次数,为后面数字大小+1。

例如1211这个数字,整个数位DP的过程是:0,1~9,10~99,100~999,1000~1199,1200~1209,1210~1211。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=,M=;
int a[M];
ll fac[M];
struct cyc{
ll a[];
}f[N][N];
cyc operator + (cyc a,cyc b){
cyc c;
for(int i=;i<=;i++)c.a[i]=a.a[i]+b.a[i];
return c;
}
cyc dp(ll num){
int len=;
cyc ans;
for(int i=;i<=;i++)ans.a[i]=;
ans.a[]=;
if(!num)return ans;
ll number=num;
while(num){
a[++len]=num%;
num/=;
}
for(int i=;i<len;i++)for(int j=;j<=;j++)ans=ans+f[i][j];
for(int i=len;i>=;i--){
for(int j=(i==len);j<a[i];j++){
ans=ans+f[i][j];
}
number%=fac[i-];
ans.a[a[i]]+=number+;
}
//for(int k=0;k<=9;k++)printf("%d ",ans.a[k]);puts("");
return ans;
}
int main(){
fac[]=;for(int i=;i<=N;i++)fac[i]=fac[i-]*;
for(int j=;j<=;j++)f[][j].a[j]=;
for(int i=;i<=N;i++){
for(int j=;j<=;j++){
for(int k=;k<=;k++){
f[i][j]=f[i][j]+f[i-][k];
f[i][j].a[j]+=fac[i-];
}//printf("[%d][%d]",i,j);
//for(int k=0;k<=9;k++)printf("%d ",f[i][j].a[k]);puts("");
}
}
ll A,B;scanf("%lld%lld",&A,&B);
cyc cA=dp(A-),cB=dp(B);
for(int i=;i<;i++)printf("%lld ",cB.a[i]-cA.a[i]);
printf("%lld",cB.a[]-cA.a[]);
return ;
}

【BZOJ】1833 [ZJOI2010]count 数字计数的更多相关文章

  1. BZOJ 1833: [ZJOI2010]count 数字计数( dp )

    dp(i, j, k)表示共i位, 最高位是j, 数字k出现次数. 预处理出来. 差分答案, 对于0~x的答案, 从低位到高位进行讨论 -------------------------------- ...

  2. [BZOJ 1833] [ZJOI2010] count 数字计数 【数位DP】

    题目链接:BZOJ - 1833 题目分析 数位DP .. 用 f[i][j][k] 表示第 i 位是 j 的 i 位数共有多少个数码 k . 然后差分询问...Get()中注意一下,如果固定了第 i ...

  3. BZOJ 1833: [ZJOI2010]count 数字计数

    Description 问 \([L,R]\) 中0-9的个数. Sol 数位DP. 预处理好长度为 \(i\), 最高位为 \(j\) 的数位之和. 然后从上往下计算,不要忘记往下走的同时要把高位的 ...

  4. bzoj 1833 [ZJOI2010]count 数字计数(数位DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1833 [题意] 统计[a,b]区间内各数位出现的次数. [思路] 设f[i][j][k ...

  5. BZOJ 1833 ZJOI2010 count 数字计数 数位DP

    题目大意:求[a,b]间全部的整数中0~9每一个数字出现了几次 令f[i]为i位数(算前导零)中每一个数出现的次数(一定是同样的,所以仅仅记录一个即可了) 有f[i]=f[i-1]*10+10^(i- ...

  6. bzoj 1833: [ZJOI2010]count 数字计数【数位dp】

    非典型数位dp 先预处理出f[i][j][k]表示从后往前第i位为j时k的个数,然后把答案转换为ans(r)-ans(l-1),用预处理出的f数组dp出f即可(可能也不是dp吧--) #include ...

  7. 1833: [ZJOI2010]count 数字计数

    1833: [ZJOI2010]count 数字计数 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 2951  Solved: 1307[Submit][ ...

  8. 1833: [ZJOI2010]count 数字计数 - BZOJ

    Description给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次.Input输入文件中仅包含一行两个整数a.b,含义如上所述.Output输出文件中包含一 ...

  9. 【BZOJ】1833: [ZJOI2010] count 数字计数(数位dp)

    题目 传送门:QWQ 分析 蒟蒻不会数位dp,又是现学的 用$ dp[i][j][k] $ 表示表示长度为i开头j的所有数字中k的个数 然后预处理出这个数组,再计算答案 代码 #include < ...

随机推荐

  1. FZU.Software Engineering1816 · First Homework -Preparation

    Introduction 041602204 : 我是喜欢狗狗(particularly Corgi & Shiba Inu.)的丁水源 : 我的爱好是音乐.电影.英语(100%!!!!).吉 ...

  2. 【Docker 命令】- kill命令

    docker kill :杀掉一个运行中的容器. 语法 docker kill [OPTIONS] CONTAINER [CONTAINER...] OPTIONS说明: -s :向容器发送一个信号 ...

  3. 【Redis】- 双写一致性

    首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用.在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作. 但是在更新缓存方面,对于更新完数据库,是更新缓存呢,还是删除缓存.又或者 ...

  4. 第一章 持续集成jenkins工具使用之部署

    1.1 硬件要求 内存:至少512MB 磁盘空间:10G JDK8 最好同时安装jre 从官网https://jenkins.io/download/下载最新的war包(Generic Java Pa ...

  5. PHPCMS登录后不是进入会员中心而是转入登录前页最新代码

    phpcms比如会员在登录前是停留在下载页面的,但是下载页面是要求会员登录后才能下载,所以会员就有这个登陆过程,但是一般的会员系统是登录进会员中心的,就会有点体验不好  这里教大家修改下 能达到登录后 ...

  6. Delphi:ADOConnection连接SQLServer自动断网问题解决

    =============================== 解决方法一:异常时关闭连接,WinXP,win7 32位大部分情况都是起作用的,不过在有些windows操作系统下(如家庭版)不起作用, ...

  7. Shell中sort-cut-wc详解

    sort sort 命令对 File 参数指定的文件中的行排序,并将结果写到标准输出.如果 File 参数指定多个文件,那么 sort 命令将这些文件连接起来,并当作一个文件进行排序. sort语法 ...

  8. 【bzoj2073】[POI2004]PRZ 状态压缩dp

    题目描述 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍在桥上的人都不能超过一定的限制. 所以这只队伍过桥时只能分批 ...

  9. BZOJ4299 Codechef FRBSUM(主席树)

    感觉非常不可做,于是考虑有什么奇怪的性质. 先考虑怎么求子集和mex.将数从小到大排序,假设已经凑出了0~n的所有数,如果下一个数>n+1显然mex就是n+1了,否则若其为x则可以凑出1~n+x ...

  10. [SOJ #47]集合并卷积

    题目大意:给你两个多项式$A,B$,求多项式$C$使得:$$C_n=\sum\limits_{x|y=n}A_xB_y$$题解:$FWT$,他可以解决形如$C_n=\sum\limits_{x\opl ...