AtCoder Regular Contest 149 - A - Repdigit Number - 题解

171 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 300300 points

Problem Statement

You are given positive integers NN and MM. Find the maximum positive integer XX that satisfies all of the following conditions.

  • XX is a positive integer less than 10N10^N, and all digits in the decimal representation of XX are the same.
  • XX is a multiple of MM.

If no positive integer XX satisfies the conditions, print -1.

Constraints

  • 1≤N≤1051\leq N\leq 10^5
  • 1≤M≤1091\leq M\leq 10^9

Input

The input is given from Standard Input in the following format:

NN MM

Output

Print the maximum positive integer XX that satisfies all of the conditions, or -1 if no such positive integer XX exists.


Sample Input 1

7 12

Sample Output 1

888888

Four positive integers XX satisfy the conditions: 444,888,444444,888888444, 888, 444444, 888888. The answer is the maximum of them, which is 888888888888.


Sample Input 2

9 12

Sample Output 2

888888888

Six positive integers XX satisfy the conditions: 444,888,444444,888888,444444444,888888888444, 888, 444444, 888888, 444444444, 888888888.


Sample Input 3

1 3

Sample Output 3

9

Three positive integers XX satisfy the conditions: 3,6,93, 6, 9.


Sample Input 4

1000 25

Sample Output 4

-1

No positive integers XX satisfy the conditions.


Sample Input 5

30 1

Sample Output 5

999999999999999999999999999999

题目大意

给你两个正整数NNMM,让你找到最大的 形如11111...1的数,其中这个数不大于NN,并且这个数能被MM整除

解题思路

首先想想怎么暴力。暴力的话,Python自带大整数,而C++则需要手写高精度。

以数字1为例,那么暴力无非就是:

  • 1开始尝试,接着尝试11111...1111...1,看看哪个数能整除MM。如果能整除MM,就更新答案的最大值。

但是这样肯定超时,因为NN的最大值是10510^5,也就是说最多尝试到1111...1(100000个1)。

构造出这个有100000个1的数字,再让它除以MM,光是这一步的时间复杂度就是O(N)O(N)

11个1到NN个1,时间复杂度同样是O(N)O(N),因此,总时间复杂度为O(N2)O(N^2)

那么,有没有一种办法,能够优化一个维度呢?有没有办法不适用大整数,而是直接使用64位整数(如C语言的long long)存下整个运算过程的结果呢?

这让我们想到了取模。

取模有以下两种性质:

  1. (x+y)%MOD=((x%MOD)+(y%MOD))%MOD(x+y)\% MOD = ((x \% MOD) +(y\% MOD))\%MOD
  2. (x×y)%MOD=((x%MOD)×(y%MOD))%MOD(x\times y)\% MOD = ((x \% MOD) \times (y\% MOD))\%MOD

说人话就是:加法和乘法运算不改变取模结果。

取模好啊,取模后,就能用64位整数存下了。

在计算过111的基础上,有没有办法,在O(1)O(1)的时间复杂度内,计算出1111的结果呢?

1111=11110+11111 = 111 * 10 + 11111%M=((111%M)10+1)%M1111 \% M = ((111 \% M) * 10 + 1) \% M

同时,111...1111...1能整除MM,等价于111...1%M=0111...1 \% M = 0

所以,问题解决啦!

先考虑111...11...1, 从1开始,然后在1的结果上计算11,再在11的基础上计算111,直到计算到NN1为止。

for (int j = 0; j < n; j++) {
    num = num * 10 + i;
    num %= MOD;
    if (num == 0) {
        更新答案最大值,记录下来是j个i
    }
}

如果中间过程中,取模结果为0,那么就更新答案的最大值(记录下来是多少个几)

之后考虑222...2333..3...999..9

最后输出jjii即可

总时间复杂度O(N)O(N),空间复杂度O(1)O(1)


AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int main() {
    int n, m;
    cin >> n >> m;
    int maxI = -1, maxJ = -1;
    for (int i = 1; i < 10; i++) {
        ll num = i;
        for (int j = 0; j < n; j++) {
            num %= m;
            if (num == 0) {
                if (j + 1 >= maxJ) {
                    maxI = i, maxJ = j + 1;
                }
            }
            num = num * 10 + i;
        }
    }
    if (maxI == -1) {
        puts("-1");
        return 0;
    }
    for (int i = 0; i < maxJ; i++) {
        putchar('0' + maxI);
    }
    return 0;
}

同步发文于CSDN,原创不易,转载请附上原文链接哦~ Tisfy:letmefly.blog.csdn.net/article/det…