用分而治之

时间:2014-08-26 20:23:43

标签: c divide-and-conquer

所以,我有一个问题。

输入包含两个数字NMN基本上告诉我们1将出现的数量,M是数字,我们用它来分割并返回余数。

1≤N≤10^16
2≤M≤10^9

Sample input:
3 3
4 7
5 18

Sample output:
0
5   
5

说明:

111 % 3 = 0
1111 % 7 = 5
11111%18 = 5 

时间限制:最多1秒

由于输入非常大,我显然不能使用模运算符。我在考虑按位运算符,但这也不会让我接受时间限制。有任何想法吗?谢谢!

2 个答案:

答案 0 :(得分:1)

我希望这不是Project Euler或其他类似的网站。

首先,数字1111...被命名为Repunit

作为modular arithmetic州:

如果a1 = b1 mod na2 = b2 mod n则:

a1 + a2 = b1 + b2 mod n
a1 - a2 = b1 - b2 mod n
a1 * a2 = b1 * b2 mod n

size n的Repunits可以在基数10中写成:1*10^n + 1*10^(n-1) ... + 1*10 + 1

这将是1*10^n + 1*10^(n-1) ... + 1*10 + 1 = X mod n

1 = x1 mod n
x1*10 + 1 = x2 mod n
x2*10 + 1 = x3 mod n
...
x(n-1)*10 + 1 = X mod n

最后的模块化结果将是解决方案:

C ++中的代码,Steve Cox的更新代码建议:

#include <iostream>
#include <map>
#include <cmath>

long long repunit_module(long long repunit_size, long long n) {
    if (repunit_size < 100) {
        // Calculate normally
        long long module_value = 1;
        for (long long i = 2; i <= repunit_size; i++) {
            module_value = (module_value * 10 + 1) % n;
        }
        return module_value;
    } else {
        // x(2n) = (x(n+1) - x(n) + 1) * x(n)
        long long xn = repunit_module(repunit_size / 2, n); // x(n) mod n
        long long xn1 = (xn * 10 + 1) % n; // x(n+1) mod n
        long long rest = xn1 - xn + 1; 
        if (rest < 0) // normalyze for module
            rest += n;
        long long result = ((rest % n) * xn) % n;

        if (repunit_size % 2 == 1) { // if size is 2n + 1 calc the last
            return (result * 10 + 1) % n;
        } else { // if size is 
            return result;
        }
    }    
}

int main() {
    long long rps = std::pow(10, 16);
    std::cout << repunit_module(3, 3) << std::endl;
    std::cout << repunit_module(4, 7) << std::endl;
    std::cout << repunit_module(5, 18) << std::endl;
    std::cout << repunit_module(rps, 123456789) << std::endl;
}

答案 1 :(得分:0)

好吧NetVipeC的回答变得非常难看

这个答案基于三个身份

x(1) = 1
x(n) = x(n-1) * 10 + 1
x(2n) = x(n)*(x(n)*9 + 2)

这些也支持Z_M。

我自下而上地写下了这些身份,但实现是自上而下的,因为它简单得多。

#include <stdio.h>

long long modulo(long long n, long long m) {
    if (n == 1) return 1;
    long long mod = modulo(n / 2, m);
    long long whole = ((mod * 9 + 2) * mod) % m;
    if(n & 1)
        return (whole * 10 + 1) % m;
    return whole;
}

int main() {
    printf("%ld\n", modulo(3, 3));
    printf("%ld\n", modulo(4, 7));
    printf("%ld\n", modulo(5, 18));
    printf("%ld\n", modulo(1e6, 123456789));
    printf("%ld\n", modulo(1e15, 123456789));
}

输出:

time ./tst
0
5
5
1239742
93889873
./tst  0.00s user 0.00s system 56% cpu 0.002 total