bzoj1833[ZJOI2010]count 数字计数 数位DP

本文介绍了一种使用数位动态规划(DP)的方法来解决特定范围内各个数字(0-9)出现次数的问题。通过定义状态转移方程并采用记忆化搜索减少重复计算,有效地解决了该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:求l,r中0-9各个数字的出现次数。
好像是数位DP经典题。。设f[i][j][k]表示做到第i位,当前计算数字j,前i-1位已经出现的次数为k的总出现次数。直接记忆化搜索即可,注意一下前导0.

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
typedef long long ll;
int dig[N];
ll f[50][50][50];
inline ll dfs(int x,int num,ll sum,bool tou,bool lim)
{
    if (!x)return sum;
    if (!lim&&!tou&&f[x][num][sum]!=-1)
    return f[x][num][sum];
    int n=lim?dig[x]:9;
    ll ans=0;
    if (!tou||x==1)ans+=dfs(x-1,num,sum+(num==0),0,lim&&dig[x]==0);
    else ans+=dfs(x-1,num,sum,1,lim&&dig[x]==0);

    fo(i,1,n)
        ans+=dfs(x-1,num,sum+(num==i),0,lim&&dig[x]==i);
    if (!lim&&!tou)f[x][num][sum]=ans;
    return ans;     
}
ll solve(ll x,int num)
{
    if (x<0)return 0;
    if (!x)return num==0?1:0;
    int t=0;
    while(x)
    {
        dig[++t]=x%10;
        x/=10;
    }
    return dfs(t,num,0,1,1);
}
int main()
{
    int cas;
    memset(f,-1,sizeof(f));
    ll x,y;
    scanf("%lld%lld",&x,&y);
    fo(i,0,8)
    printf("%lld ",solve(y,i)-solve(x-1,i));
    printf("%lld\n",solve(y,9)-solve(x-1,9));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值