问题描述
所以,我现在正在学习竞争性编程,主题是“模块化算术”。据说可以用 (a*b) % c = ((a % c) * (b % c)) % c 这本书告诉我可以使用它计算阶乘而不会出现数字溢出。但是在这个例子中,据说你可以像这样对每个操作进行 mod :
long long x = 1;
for (int i = 2; i <= n; i++) {
x = (x*i) % m; // a mod number of some kind
}
cout << x % m << '\n';
所以,问题是:像 ((x % c) * (i % c)) % c 这样使用不是更好吗?所以我们不会冒“i”数字溢出的风险?
解决方法
像 ((x % c) * (i % c)) % c
一样使用它不是更好吗?
在示例中,m
的值是否适合 32 位整数?
如果为真,x
和 i
的值也是 32 位的,这意味着只有一次乘法不会溢出,因为 x
可以包含 64 位整数。所以是安全的。
如果不是,即使我们用 ((x % m * (i % m)) % m
替换计算,它仍然可能溢出,因为 x % m
可能大于 32 位整数。所以我不认为是这样。
所以两种方式都有效。而且您的方式不会改变算法的时间复杂度。然而它没有任何优势,只是更多的计算和更多的输入:)
我想再提一个:
这本书告诉我可以使用它计算阶乘而不会出现数字溢出。
不,我们可以用这种方式计算阶乘模 m
。
在竞争性编程中,大多数问题都避免了通过这种方式答案变得太大的问题。所以我们总是可以在恒定时间(没有大整数)计算算术运算。