首页 > 试题广场 >

被3整除

[编程题]被3整除
  • 热度指数:312 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

小Q得到一个神奇的数列: 1, 12, 123,...12345678910,1234567891011...。

并且小Q对于能否被3整除这个性质很感兴趣。

小Q现在希望你能帮他计算一下从数列的第l个到第r个(包含端点)有多少个数可以被3整除。


输入描述:
输入包括两个整数l和r(1 <= l <= r <= 1e9), 表示要求解的区间两端。


输出描述:
输出一个整数, 表示区间内能被3整除的数字个数。
示例1

输入

2 5

输出

3

说明

12, 123, 1234, 12345...
其中12, 123, 12345能被3整除。
我们需要依次考察区间[l,r]中哪些数可以被3整除,被3整除的数需要各位数字加起来仍然能被3整除。但题中所给的数据范围较大,如果依次将各位进行累加,每个数遍历的长度最大会超过整型的范围,时间复杂度过高。我们可以分析:对于12345678910,这个数要想知道它是否能被3整除,需要计算(1+2+3+4+5+6+7+8+9+1+0)%3是否能够得到0,但实际上我们只需要求1~10的和就行了,因为即使是加上10,考虑能不能被3整除也同样是计算1+0能否被3整除,也就是说拆开累加与直接累加是等效的。而直接累加的话根据高斯求和公式,时间复杂度可以达到O(1)级别,考察区间[l,r]上能够被3整除的数个数整体上的时间复杂度为O(r-l),是一个跟数据规模相关的线性复杂度。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().split(" ");
        int l = Integer.parseInt(params[0]), r = Integer.parseInt(params[1]);
        int count = 0;
        for(int num = l; num <= r; num++){
            long sum = ((1L + num) * num) >> 1;
            if(sum % 3 == 0) count++;
        }
        System.out.println(count);
    }
}

编辑于 2021-11-28 11:23:22 回复(0)
l,r=list(map(int,input().strip().split()))
r=(r//3)*2+(1 if r%3==2 else 0)
l=((l-1)//3)*2+(1 if (l-1)%3==2 else 0)
print(r-l)
发表于 2019-08-03 14:00:06 回复(1)
n,m =[int(i) fori ininput().split()]
defcount_number(x):
    ifx%3==2:
        return(x//3)*2+1
    else:
        return(x//3)*2
print(count_number(m)-count_number(n-1))
 语言:Python 3 运行时间: 22 ms 占用内存:3560K

发表于 2018-08-16 17:50:27 回复(3)
using System;
public class DividedByThreeClass
    {
        /**
         * ACM链接:https://www.nowcoder.com/questionTerminal/00f3f6fc145b4d3ea5ab460f957ec8fc?orderByHotValue=0&questionTypes=000100&mutiTagIds=149&page=7&onlyReference=false
         * 小Q得到一个神奇的数列: 1, 12, 123,...12345678910,1234567891011...。
         * 并且小Q对于能否被3整除这个性质很感兴趣。
         * 小Q现在希望你能帮他计算一下从数列的第l个到第r个(包含端点)有多少个数可以被3整除。
         */
        // 别的语言过的了 C#时间上过不了的代码 有点奇怪 对数器校验是没错的
        private static long DividedByThreeNoPass( int l, int r )
        {
    
            long res = 0;
            for (long i = l; i <= r; i++) if ( (((1 + i) * i) >> 1) % 3 == 0  )res++;
            return res;
        }
        
        
        // 打表法
        // 直接找规律  可以发现从1开始三个是一组  为false true true
        
        // 求解1 - end上有多少个能被3整除 O(1)
        private static long CalNum(long end)
        {
            if (end < 1) return 0;
            long res = end / 3 * 2 ;
            long endNum = end % 3;
            if (endNum > 0) res += endNum - 1;
            return res;
        }
        
        private static long DividedByThree( long l, long r)
        {
            long num1 = CalNum(l - 1);
          long num2 = CalNum(r);
          return num2 - num1;
        }
        
        // 对数器
        private static void Test()
        {
            int testTime = 1000;
            int big = 1000000000;
            int bigLength = 1000;
            Random random = new Random();
            for (int i = 0; i < testTime; i++)
            {
                int l = random.Next(1, big);
                int length = random.Next(1, bigLength);
                int r = random.Next(l + length, big);
                long ans1 = DividedByThree(l, r);
                long ans2 = DividedByThreeNoPass(l, r);
                if (ans1 != ans2)
                {
                    Console.WriteLine( $"用例:[{l}, {r}]   结果不通过  OJ方法结果:{ ans1 }   超时方法结果:{ ans2 } " );
                    return;
                }
            }
            Console.WriteLine("超时方法校验通过");

        }

        public static void Main(string[] args)
        {
            // string input = Console.ReadLine();
            // if (input != null)
            // {
            //     string[] param = input.Split(' ');
            //     Console.WriteLine( DividedByThree(long.Parse(param[0]), long.Parse(param[1]))  );
            // }
            Test();
        }
    }
c#的话常规的O(n)方法过不了 必须是打表法的O(1)才能过
发表于 2022-07-29 11:51:40 回复(0)