• 数码


    题目描述:
         给定两个整数 l 和 r ,对于所有满足1 ≤ l ≤ x ≤ r ≤ 10^9 的 x ,把 x 的所有约数全部写下来。对于每个写下来的数,只保留最高位的那个数码。求1~9每个数码出现的次数。

    样例输入

    1 4

    样例输出

    4

    2

    1

    1

    0

    0

    0

    0

    0

    数据范围

      n,m<=10^9


    心态崩了,这是lv神考试的Day5 T1

    看上去是个大水题,直接模拟呗,结果一看数据范围,顿时懵逼

    我们年级其他的同学基本上都很明智的弃了,只有我还在很傻的写题(怎么如此耳熟)

    既然要写,就一定要有效果,所以在一番深思熟虑后,我决定写一个暴力

    是的,就是一个暴力,很符合社会主义价值观的暴力,然后加了一点小小的优化

    比如说,在求约数的时候,将上限定为sqrt(x),然后就跑的fo快

    然后又不由自主的开始打表,无奈数据实在太大,最后电脑卡了,我代码还没存

    伤心到变形,然后发现暴力能拿五十分,就开心的不得鸟

    估算了一下,打表的话大概是可以到10^8左右(要跑三个小时)

    具体代码如下:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    using namespace std;
    inline int rd(){
       int x=0,f=1;
       char ch=getchar();
       for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
       for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
       return x*f;
    }
    inline void write(int x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    int l,r;
    int ans[106];
    void solve(int x){
        for(register int i=1;i<=sqrt(x);i++){
            if(x%i!=0) continue;
            int set=0;
            int h=i;
            while(h){
                set=h%10;
                h/=10;
            }
            ans[set]++;
            if(i*i!=x){
                if(i>sqrt(x)) continue;
                h=x/i;
                while(h){
                    set=h%10;
                    h/=10;
                }
                ans[set]++;
            }
        }
        return ;
    }
    int main(){
        int l=rd(),r=rd();
        for(register int i=l;i<=r;i++) solve(i);
        for(register int i=1;i<=9;i++){
            write(ans[i]);
            puts("");
        }
        return 0;
    }

    然后考完了去学习正解,发现是个数论题(其实谁都知道是数论,但就是不会写QAQ)

    我们不难发现,暴力是绝对会T的,所以在计算的时候不能每次加一,而是要每次加一个区间的值

    所以转换思路,我们知道两个数啊,a,b的乘积在区间l到r之间的话,a和b就都是合法的,所以我们来枚举a这个数,之后再判断b是否与a重复就可以了

    具体代码如下:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    using namespace std;
    inline long long rd(){
       long long x=0,f=1;
       char ch=getchar();
       for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
       for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
       return x*f;
    }
    inline void write(long long x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    long long n,m;
    long long cnt[10];
    long long gets(long long l,long long r,long long x){
        long long sum=0;
        if(x<r) r=x;//确定边界 
        long long md=x%r;
        long long num=x/r;//num枚举的就是上文中的a 
        while(1){
            long long f=(r-md)/(num+1);//是上文的b 
            if(f*(num+1)<r-md) f++;
            if(l+f>r) break;//超出边界 
            sum+=f*num;
            md=(num*f+md)%(r-f);
            r-=f;
            if(f==1) num=(x/r);
            else num++;
        }
        return sum+(r-l+1)*num;
    }
    void solve(long long x,long long y){//x表示右端点,y表示是加还是减 
        for(long long i=1;i<=9;i++){
            long long set=1;//处理不同的数位的时候,枚举10^i 
            while(1){
                if(i*set>x) break;//保证要处理的数的数位足够多 
                cnt[i]+=y*gets(i*set,((i+1)*set)-1,x);//当前数位所有的数 
                set*=10;//10的次方 
            }
        }
        return ;
    }
    int main(){
        n=rd(),m=rd();
        solve(m,1);//处理的时候因为不好枚举从l到r,所以我们计算出从1分别到l-1和r,然后作差就可以了(很像数位dp) 
        solve(n-1,-1);
        for(long long i=1;i<=9;i++){
            write(cnt[i]);
            puts("");
        }
        return 0;
    }
    蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿
  • 相关阅读:
    git各种操作:基本操作 and 多人协作 and 冲突解决
    mini-ndn0.5.0 安装教程 (避免踩坑)
    ubuntu18.04 更换镜像源
    自定义日志轮转
    linux常用命令
    Thinkphp6 + uniapp框架,接口访问跨域问题
    机器学习-主成分分析PCA与奇异值分解SVD
    机器学习-数据预处理&特征工程
    机器学习-梯度提升树(xgboost)
    github打不开怎么办
  • 原文地址:https://www.cnblogs.com/WWHHTT/p/9703523.html
Copyright © 2020-2023  润新知