📜  模数10 ^ 9 + 7(1000000007)

📅  最后修改于: 2021-04-29 03:14:10             🧑  作者: Mango

在大多数编程比赛中,我们都需要以10 ^ 9 + 7模为模来回答结果。这背后的原因是,如果问题约束是大整数,则只有有效的算法才能在允许的有限时间内解决它们。
什么是模运算:
在两个操作数上进行除法运算后获得的余数称为模运算。进行模运算的运算符为‘%’ 。例如:a%b = c,这意味着,当a除以b时,它将得到余数c,7%2 = 1、17%3 = 2。
为什么我们需要取模:

  • 采用Mod的原因是为了防止整数溢出。 C / C++中最大的整数数据类型是64位无符号long long int ,可以处理从0到(2 ^ 64 – 1)的整数。但是,在某些产出增长率很高的问题中,这种高范围的无符号长久可能是不够的。
    假设在64位变量’A’中存储2 ^ 62,在另一个64位变量’B’中存储2 ^ 63。当我们将A和B相乘时,系统不会给出运行时错误或异常。它只是进行一些伪计算并存储伪结果,因为结果的位大小是在乘法溢出后得出的。
  • 在某些问题中,需要计算模逆的结果,并且该数很有用,因为它是质数。同样,这个数字应该足够大,否则在某些情况下模块化逆向技术可能会失败。

由于这些原因,问题解决者需要对一些数字N取模来给出答案。
N的值取决于某些条件:

  1. 它应该足够大以适合最大的整数数据类型,即确保没有结果溢出。
  2. 它应该是质数,因为如果我们将质数取为质数,则结果通常是隔开的,即与非质数的数相比,结果是非常不同的结果,这就是质数通常用于质数的原因。

10 ^ 9 + 7符合这两个条件。它是第一个10位数的质数,也适合int数据类型。实际上,任何小于2 ^ 30的质数都可以,以防止可能的溢出。
模数的使用方式:
模的一些分布特性如下:

  1. (a + b)%c =((a%c)+(b%c))%c
  2. (a * b)%c =((a%c)*(b%c))%c
  3. (a – b)%c =((a%c)–(b%c))%c
  4. (a / b)%c =((a%c)/(b%c))%c

因此,模是分布在+,*和–上,而不是分布在/ [请参考模块化部门以获取详细信息]
注意: (a%b)的结果将始终小于b。
在计算机程序的情况下,由于变量限制的大小,我们在每个中间阶段执行模M,这样就不会发生范围溢出。

Example:
a = 145785635595363569532135132
b = 3151635135413512165131321321
c = 999874455222222200651351351
m = 1000000007
Print (a*b*c)%m.

Method 1:
First, multiply all the number and then take modulo:
(a*b*c)%m = (459405448184212290893339835148809
515332440033400818566717735644307024625348601572) % 
1000000007
a*b*c does not fit even in the unsigned long long 
int due to which system drop some of its most 
significant digits. Therefore, it gives the wrong answer.
(a*b*c)%m = 798848767

Method 2:
Take modulo at each intermediate steps:
i = 1
i = (i*a) % m    // i = 508086243
i = (i*b) % m    // i = 144702857
i = (i*c) % m    // i = 798848767
i = 798848767 

Method 2 always gives the correct answer.

使用模但在不同位置查找大量阶乘的函数。

C++
unsigned long long factorial(int n)
{
    const unsigned int M = 1000000007;
    unsigned long long f = 1;
 
    for (int i = 1; i <= n; i++)
        f = f * i;  // WRONG APPROACH as
                    // f may exceed (2^64 - 1)
 
    return f % M;
}


Java
static long factorial(int n)
{
    const long M = 1000000007;
    long f = 1;
 
    for (int i = 1; i <= n; i++)
        f = f * i;  // WRONG APPROACH as
                    // f may exceed (2^64 - 1)
 
    return f % M;
}
 
// This code is contributed by rutvik_56.


Python3
def factorial( n) :
    M = 1000000007
    f = 1
 
    for i in range(1, n + 1):
        f = f * i # WRONG APPROACH as
                  # f may exceed (2^64 - 1)
 
    return f % M
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)


C#
static long factorial(int n)
{
    const long M = 1000000007;
    long f = 1;
 
    for (int i = 1; i <= n; i++)
        f = f * i;  // WRONG APPROACH as
                    // f may exceed (2^64 - 1)
 
    return f % M;
}
 
// This code is contributed by pratham76.


C++
unsigned long long factorial(int n)
{
    const unsigned int M = 1000000007;
 
    unsigned long long f = 1;
    for (int i = 1; i <= n; i++)
        f = (f*i) % M;  // Now f never can
                        // exceed 10^9+7
    return f;
}


Java
static long factorial(int n)
{
    long M = 1000000007;
 
    long f = 1;
    for (int i = 1; i <= n; i++)
        f = (f*i) % M;  // Now f never can
                        // exceed 10^9+7
    return f;
}
 
// This code is contributed by Dharanendra L V.


Python3
def factorial( n) :
    M = 1000000007
    f = 1
 
    for i in range(1, n + 1):
        f = (f * i) % M # Now f never can
                        # exceed 10^9+7
 
    return f
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)


C#
static long factorial(int n)
{
    long M = 1000000007;
 
    long f = 1;
    for (int i = 1; i <= n; i++)
        f = (f*i) % M;  // Now f never can
                        // exceed 10^9+7
    return f;
}
 
// This code is contributed by Dharanendra L V.


C++
int mod(int a, int m)
{
    return (a%m + m) % m;
}


Java
static int mod(int a, int m)
{
    return (a%m + m) % m;
}
// This code is contributed by
//Shubham Singh(SHUBHAMSINGH10)


Python3
def mod(a, m):
    return (a%m + m) % m
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)


C#
static int mod(int a, int m)
{
    return (a % m + m) % m;
}
 
// This code is contributed by
//Shubham Singh(SHUBHAMSINGH10)


C++

unsigned long long factorial(int n)
{
    const unsigned int M = 1000000007;
 
    unsigned long long f = 1;
    for (int i = 1; i <= n; i++)
        f = (f*i) % M;  // Now f never can
                        // exceed 10^9+7
    return f;
}

Java

static long factorial(int n)
{
    long M = 1000000007;
 
    long f = 1;
    for (int i = 1; i <= n; i++)
        f = (f*i) % M;  // Now f never can
                        // exceed 10^9+7
    return f;
}
 
// This code is contributed by Dharanendra L V.

Python3

def factorial( n) :
    M = 1000000007
    f = 1
 
    for i in range(1, n + 1):
        f = (f * i) % M # Now f never can
                        # exceed 10^9+7
 
    return f
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)

C#

static long factorial(int n)
{
    long M = 1000000007;
 
    long f = 1;
    for (int i = 1; i <= n; i++)
        f = (f*i) % M;  // Now f never can
                        // exceed 10^9+7
    return f;
}
 
// This code is contributed by Dharanendra L V.

可以遵循相同的步骤进行添加。
(a + b + c)%M与((((a + b)%M)+ c)%M相同。
每次添加数字时都要执行%M,以避免溢出。

注意:在大多数编程语言中(如C / C++),当您使用负数执行模块化运算时,它会给出负结果,如-5%3 = -2,但是模块化运算后的结果应在范围内0到n-1表示-5%3 =1。因此,将其转换为正模等效值。

C++

int mod(int a, int m)
{
    return (a%m + m) % m;
}

Java

static int mod(int a, int m)
{
    return (a%m + m) % m;
}
// This code is contributed by
//Shubham Singh(SHUBHAMSINGH10)

Python3

def mod(a, m):
    return (a%m + m) % m
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)

C#

static int mod(int a, int m)
{
    return (a % m + m) % m;
}
 
// This code is contributed by
//Shubham Singh(SHUBHAMSINGH10)

但是划分的规则是不同的。为了进行模运算除法,我们首先需要了解模乘法逆的概念。

模乘逆(MMI):
数y的乘法逆是z iff(z * y)== 1。
将数字x除以另一个数字y等于将x乘以y的乘法逆。
x / y == x * y ^(-1)== x * z(其中z是y的乘法逆)。
在常规算术中,y的乘法逆是浮点值。例如:7的乘法逆是0.142…,3的乘法逆是0.333…。
在数学中,整数“ a”的模乘乘法逆是整数“ x”,以使得乘积ax相对于模数m等于1。
轴= 1(mod m)
将ax除以整数m后的余数为1。

Example:
If M = 7, the MMI of 4 is 2 as (4 * 2) %7 == 1,
If M = 11, the MMI of 7 is 8 as (7 * 8) % 11 == 1,
If M = 13, the MMI of 7 is 2 as (7 * 2) % 13 == 1.

观察到一个数字的MMI对于不同的M可能会有所不同。
因此,如果我们在程序中执行模算术,并且需要运算x / y的结果,则不应执行

z = (x/y) % M;

相反,我们应该执行

y_inv = findMMI(y, M);
z = (x * y_inv) % M;