牛客网系列--网易2019实习生招聘编程题--数对

题目:

牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。牛牛希望你能帮他计算一共有多少个可能的数对。

输入描述:
输入包括两个正整数n,k(1 <= n <= 10^5, 0 <= k <= n - 1)。
输出描述:
对于每个测试用例, 输出一个正整数表示可能的数对数量。

示例1

输入

5 2

输出

7

说明

满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)

解题思路:

当我们确定了除数y的时候,我们会发现,对于x取任意的1-n中的数字,都会得到以下的余数数列:

1 2 3 4 5 ... (y-1) 0
1 2 3 4 5 ... (y-1) 0
...

可以看到,余数的出现是存在循环的,每y个数余数就完成一次循环。当然最后一个循环可能只会有几个数,构不成一个循环,所以要分开来算。

算法中有三个变量需要我们计算:

  • 循环次数
  • 满循环时符合条件的余数数量
  • 最后一个循环中符合条件的余数数量

有了这三个变量之后,我们就可以开始写对于y = i的情况,所有符合条件的x的数量。

res += (loopNum * (otherLoop > 0 ? otherLoop : 0) + (lastLoop > 0 ? lastLoop : 0));

最后把i为k-n的所有情况加总就可以得到正确解。

时间复杂度:O(N)

空间复杂度:O(1)

代码:

import java.util.Scanner;

public class NumberPair {

    public static void main(String[] args) {
        NumberPair np = new NumberPair();
        Scanner scanner = new Scanner(System.in);
        String cmd = scanner.nextLine();
        String[] cmdParams = cmd.split(" ");
        int n = Integer.parseInt(cmdParams[0]);
        int k = Integer.parseInt(cmdParams[1]);
        System.out.println(np.getNumberPair(n, k));
    }

    public long getNumberPair(int n, int k) {

        if (k == 0) return (long) n * (long) n;

        long res = 0;

        for (int i = k; i <= n; i ++) {
            /*
                n / i 表示余数的循环
                i - k + 1 表示合法的余数的数量
                n - n / i * i + 1最后一个余数循环里面最后剩下的几个余数
            */
            int lastLoop = (n - n / i * i - k + 1);
            int loopNum = (n / i);
            int otherLoop = (i - k);
//            System.out.println(i + " -> " + loopNum + " * " + otherLoop + " + " + lastLoop);
            res += (loopNum * (otherLoop > 0 ? otherLoop : 0) + (lastLoop > 0 ? lastLoop : 0));
        }

        return res;

    }

}

猜你喜欢

转载自blog.csdn.net/zhangzhetaojj/article/details/80682396