数数字

题目描述

小N对于数字的大小一直都有两种看法。第一种看法是,使用字典序的大小(也就是我们常用的判断数字大小的方法,假如比较的数字长度不同,则在较短一个前面补齐前导0,再比较字典序),比如43<355,10<11。第二种看法是,对于一个数字,定义他的权值为,也就是各个数位的乘积。 现在给定两个区间,[L,R]与[L1,R1]。小N现在想知道,有多少使用字典序判大小法在[L,R]之间的数字,满足其第二种定义的权值也在[L1,R1]之间。 换句话说,对于一个数x,定义f(x)为x的各个数位的乘积。对于L<=x<=R,问有多少x满足,L1<=f(x)<=R1。

输入描述:

第一行四个整数L,R,L1,R1。

输出描述:

一行一个整数,代表小N想知道的数的数量。

示例1

输入

34 10000 24 57

输出

777

备注:

20%: L,R <= 10000000
40%: L,R <= 3*10^7
60%: L,R,L1,R1 <= 10^9
另外有20%:L1,R1<=1000
100%: 0<=L,R,L1,R1 <= 10^18, L <= R, L1 <= R1

心得:

这题折腾死我了写了15min,debug了20min,具体哪错了就看代码吧

代码

#include<bits/stdc++.h>
using namespace std;
template<typename A>
void read(A&a)
{
    a=0;
    char c=0;
    int f=1;
    while(c<'0'||c>'9')
        (c=getchar())=='-'?f=-1:0;
    while(c>='0'&&c<='9')
        a=(a<<3)+(a<<1)+c-'0',c=getchar();
    f==-1?a=-a:0;
}
char buf[30];
template<typename A>
void write(A a)
{
    if(a<0)
        putchar('-'),a=-a;
    int top=0;
    if(!a)
        buf[top=1]='0';
    while(a)
        buf[++top]=a%10+'0',a/=10;
    while(top)
        putchar(buf[top--]);
}

long long L,R,L1,R1;int s[20];
map<long long,long long>dp[20];
long long f[20],t[20];

long long dfs(int x,long long y,int lim)
{
    if(!x)
    {
        if(y)
            return 1;
        else
            return 0;
    }//if(y==0)return 0;  好像不能只要写,因为即使是0,也可以有数字。
    if(!lim&&dp[x].count(y))
        return dp[x][y];
    long long ans=(lim?(s[x]?t[x-1]:f[x-1]+1):t[x-1]);
    for(int i=1;i<=(lim?s[x]:9);++i)
        ans+=dfs(x-1,y/i,lim&&(i==s[x]));
    return !lim?dp[x][y]=ans:ans;//错误笔记:如果有lim就不能存进数组了
}

long long Solve(long long x,long long y){//错误笔记:注意这些参数的类型也要开long long啊,不能顺手打int
    if(x<0||y<0)
        return 0;//错误笔记:<0可能要特判一下,如果按照一般的程序处理会有问题
    if(x==0)
        return 1;//错误笔记:等于0可能也要特判,因为按照一般的程序,会返回0 ,实际上应该是1
    int len=0;
    long long p=x,ans=0;//错误笔记:包括P的类型也要开long long
    while(p)
        s[++len]=p%10,p/=10;
    for(int i=1;i<=len;++i)
        f[i]=f[i-1]+s[i]*t[i-1];
    for(int i=len;i;--i)
    {
        int lim=(i==len?s[i]:9);
        for(int j=1;j<=lim;++j)
            ans+=dfs(i-1,y/j,i==len&&j==lim);
    }
    return ans;
}

int main()
{
    read(L),read(R),read(L1),read(R1);
    t[0]=1;
    for(int i=1;i<=19;++i)
        t[i]=t[i-1]*10;
    write(Solve(R,R1)-Solve(L-1,R1)-Solve(R,L1-1)+Solve(L-1,L1-1));
    putchar('\n');
}

来源:nkw

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值