牛客 数码(枚举优化+数论思维)

传送门


题面

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

分析

首先数据范围很大,问题可以转化为求 1 − ( l − 1 ) 1-(l-1) 1(l1) 1 − r 1-r 1r的数码之差。肯定不能暴力求每个数的因数。首先 1 − n 1-n 1n的因数最多有 2 n 2\sqrt{n} 2n 个,且会沿 n \sqrt{n} n 两边对称分步且成对出现。设 x = a ∗ b x=a*b x=ab,考虑枚举 1 − n 1-\sqrt{n} 1n 范围内的因数 a a a,不难计算出 b b b的取值范围 [ 1 , ⌊ r a ⌋ ] [1,⌊\frac{r}{a}⌋] [1,ar],举几个例子后不难发现只需要考虑几位数以及最高位是几,那么就枚举最高位和不超过 b b b的位数,当然得出的区间应该是 [ a + 1 , b ] [a+1,b] [a+1,b]的子区间,需要判断一下上下界的越界,之所以从 a + 1 a+1 a+1开始是为了防止算 a a a重复

最后 a a a用了几个就是 b − a + 1 b-a+1 ba+1

讲解参考了牛客精讲

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <cstdio>
#include <string>
#include <bitset>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define lowbit(x) (x&(-x))
#define mkp(x,y) make_pair(x,y)
#define mem(a,x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<double,double> pdd;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const double dinf=1e300;
const ll INF=1e18;
const int Mod=998244353;
const int maxn=2e5+10;

ll n,k;
ll num[20];

int solve(int x){
    while(x>=10) x/=10;
    return x;
}

void cal(int n,int s){
    for(int i=1;i*i<=n;i++){
        int y=n/i;
        for(int j=1;j<=n;j*=10)
            for(int k=1;k<=9;k++){
                int d=max(j*k,i+1);
                int u=min((k+1)*j-1,y);
                if(d<=u) num[k]+=(u-d+1)*s;
            }
        num[solve(i)]+=(y-i+1)*s;
    }
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int l,r;
    cin>>l>>r;
    cal(r,1);
    cal(l-1,-1);
    for(int i=1;i<=9;i++) cout<<num[i]<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值