CodeM资格赛E 数码 题解

来源:互联网 发布:养羊软件 编辑:程序博客网 时间:2024/05/16 01:28

题意

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

思路

首先我们只需要能求出从1到x的答案,然后减就好了,对于不超过x的数,就要在这个的最高位的计数上加x/x,并记录下x/x,放到栈中,对于超过x的数,就会有一段数作为约数出现在1到x中的次数都相等,而这个界线就是之前存在栈里的那些数,此时我们需要做的是能够求出1到y中对每个数取最高位那么1到9出现的次数,然后相减即可,经过这两步就可以得到题目要的结果

代码

#include <cstdio>#include <cmath>#include <stack>using namespace std;long long ans1[10],ans2[10],ad1[10],ad2[10];long long hdigit(long long x){    while(x>=10)        x/=10;    return x;}void calc2(long long x,long long *d){    long long xx=x,cnt=0,temp;    for(long long i=0;i<=9;i++)        d[i]=0;    if(x==0)        return;    while(xx>0)    {        xx/=10;        cnt++;    }    temp=1;    for(long long i=0;i<cnt-1;i++)    {        for(int j=1;j<=9;j++)            d[j]+=temp;        temp*=10;    }    for(long long i=1;i<hdigit(x);i++)        d[i]+=temp;    d[hdigit(x)]+=x-hdigit(x)*temp+1;    return;}void calc(long long x,long long* d){    for(long long i=0;i<=9;i++)        d[i]=0;    if(x==0)        return;    long long e=sqrt(x),ee;    ee=e;    stack<long long> st;    for(long long i=1;i<=e;i++)    {        d[hdigit(i)]+=x/i;        st.push(x/i);    }    while(!st.empty())    {        if(e==st.top())        {            st.pop();            ee--;            continue;        }        if(st.empty())            break;        calc2(st.top(),ad1);        calc2(e,ad2);        //printf("e:%lld sttop:%lld\n",e,st.top());        for(long long i=1;i<=9;i++)        {            //printf("%lld\n",ad1[i]-ad2[i]);            d[i]+=(ad1[i]-ad2[i])*ee;        }        e=st.top();    }    return;}int main(){    long long l,r;    scanf("%lld%lld",&l,&r);    calc(r,ans1);    calc(l-1,ans2);    for(long long i=1;i<=9;i++)        printf("%lld\n",ans1[i]-ans2[i]);    return 0;}
原创粉丝点击