FNOI_TEST_1 a

本文介绍了一种高效的算法,用于解决特定区间内所有数字的各位数字之和的问题。该算法通过预处理和逐位计算的方法,在O(9*len)的时间复杂度内得出答案,适用于大范围的数据输入。

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

http://www.elijahqi.win/archives/599
1.函数(a.cpp/c/pas)
【问题描述】 给出两个正整数 L、R,设 f(x)=x 的各位数字之和,对于所有满足 L<=x<=R 的 正整数 x,求 f(x)的和。 【输入数据】 两个正整数 L、R。 【输出数据】 一个正整数表示答案。 【输入输出样例 1】 a.in a.out 912 15 【输入输出样例 1 说明】 答案=f(9)+f(10)+f(11)+f(12)=9+(1+0)+(1+1)+(1+2)=15 【输入输出样例 2】 a.in a.out 4216790354 1168268 【输入输出样例 3】 a.in a.out 233333333233429666 3272189 【输入输出样例 4】 a.in a.out 109370421979326187 35583321682 【数据规模和约定】 测试点编号 R 特殊性质 1 <=9 2 <=100 3 <=1000 4 <=100000 5 6
<=10^9 R-L<=1000007 8 9 10 对于 100%的数据:1<=L<=R<=10^9

这题考场上刚出来了,不过总分还是好低啊qwq

看到leoly给的数据范围,于是瞬间想到太大的部分我们预处理,再看下数据范围,10^5以上的部分应该已处理下pre[i] i其实后面省略了5个0,预处理出来。然后剩下的小于10^5的地方暴力做就好

#include<cstdio>
long long pre[110000];
int l,r;
int main(){
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    scanf("%d%d",&l,&r);
    if (r<=1e5||(r-l)<=100000){
        long long ans=0;
        for (int i=l;i<=r;++i){
            int tmp=i;
            while (tmp){
                ans+=tmp%10;tmp/=10;
            }
        }
        printf("%lld",ans);    
    } else{
        //pre
        pre[0]=2250000;int tmp1=1e5,tmp2=2;
        pre[1]=pre[0];
        for (int i=2;i<=1e5;++i){
            int tmp=i-1;
            pre[i]=pre[i-1]+pre[0];
            while (tmp>0){
                pre[i]+=(tmp%10)*1e5;tmp/=10;
            }
        }
        for (int i=1;i<=1e5;++i){
            int tmp=i;
            while (tmp){
                pre[i]+=tmp%10;tmp/=10;
            }
        }
        //printf("%lld",pre[177]);
        int ll=l/100000,rr=r/100000;
        int tmp=ll;long long ans=0;
        while (tmp>0){
            ans+=(tmp%10)*(99999-(l%100000)+1);tmp/=10;
        }
        tmp=rr;
        while (tmp>0){
                ans+=(tmp%10)*(r%100000);tmp/=10;
        }
        ll+=1;
        ans+=pre[rr]-pre[ll];
        tmp=ll;
        while (tmp){
            ans+=tmp%10;tmp/=10;
        }
        ll=l%100000;
        for (int i=ll;i<=99999;++i){
            tmp=i;
            while (tmp){
                ans+=tmp%10;tmp/=10;
            }
        }
        rr=r%100000;
        for (int i=1;i<=rr;++i){
            tmp=i;
            while (tmp){
                ans+=tmp%10;tmp/=10;
            }
        }
    //    if (l%100000==0) ans+=2250000;
        printf("%lld",ans);
    }
    return 0;
}

一起看下官方题解吧

1.函数(a) 【80 分】 枚举 x 并计算 f(x),累加 f(x)得到答案。时间复杂度 O(R-L)。 【100 分】 计算十进制下每一位上每种数字出现的次数,进而算出答案。设 len 为 R 的位数, 时间复杂度 O(9*len)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int L, R, l, a[20];
ll check(int L){
    if(!L)return 0;
    l=0; int x=L; while(x){a[++l]=x%10; x/=10;}
    ll ans=0; int sum, x1, x2;
    for(int i=1; i<=l; i++)
        for(int j=1; j<=9; j++){
            sum=x1=x2=0;
            for(int k=l; k>=i+1; k--)x1=x1*10+a[k];
            x2=1; for(int k=1; k<=i-1; k++)x2*=10;
            if(j<a[i])sum=(x1+1)*x2;
            if(j>a[i])sum=x1*x2;
            if(j==a[i]){
                sum=x1*x2;
                x2=0; for(int k=i-1; k; k--)x2=x2*10+a[k]; x2++;
                sum+=x2;
            }
            ans+=sum*j;
        }
    return ans;
}
int main(){
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
    scanf("%d%d", &L, &R);
    printf("%lld", check(R)-check(L-1));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值