Sumdiv
Time Limit: 1000MS |
|
Memory Limit: 30000K |
Total Submissions: 12755 |
|
Accepted: 3100 |
Description
Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).
Input
The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.
Output
The only line of the output will contain S modulo 9901.
Sample Input
2 3
Sample Output
15
Hint
2^3 = 8.
The natural divisors of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).
Source
Romania OI 2002
题目非常好,考察的技巧很多。
1、同模余定理:
%运算对于加减乘法是随意的。可以随便打开括号。因此为了避免溢出,要经常做%运算。
2、等比数列求和:
1 + 2 + 2^2 + 2^3 ... + 2^n 计算的时候,不能用等比求和公式,因为
除法不满足同模余定理,在求余数的时候会有错误。因此使用一个小trick,用二分来解决(非常巧妙):
当n为偶数时: 1+2+...+2^n = (1 + 2 + ... + 2 ^ (n / 2)) * (1 + 2 ^ (n / 2 + 1)) - 2 ^ (n + 1)
当n为奇数时: 1+2+...+2^n = (1 + 2 + ... + 2 ^ (n / 2)) * (1 + 2 ^ (n / 2 + 1))
3、大数因子分解:
任意一个自然数都可以分解为素数次幂的乘积,而且
分解方式唯一。也就是说,分解方式与原自然数 是
一一对应的!
比如300 可以分解为 2 * 2 * 3 * 5 * 5
用数组表示就是:
素数: 2 3 5
对应个数: 2 1 2
分解算法千万不要去打素数表,因为当输入非常大(比如这题的5000万),打素数表会直接超时,即使用筛法)
直接去分解,就会自然形成素数序列(有点类似筛素数了,比如2被分解干净后,2的倍数就不会再被分解出来)
cin >> a >> b;
ll tmp = a;
int num = 0;
for (i = 2; tmp != 1 && i * i <= a; i++) { //这里是tmp != 1,终止条件是i*i <= a !!!因为所有因子中,最坏情况只能是有一个素因子大于sqrt(a),因此最后特殊考虑一下即可。
while (tmp % i == 0) {
p[num] = i;
n[num] ++;
tmp /= i;
}
if (p[num] != 0) num++;
}
if (tmp != 1) { //这里是tmp != 1!!!
p[num] = tmp;
n[num] = 1;
num++;
}
4、大数因子和:
分解出上面的数组后,其实因子和就很容易求出来了:
其实就是(1 + 2 + 2^2) * (1 + 3) * (1 + 5 + 5^2) 想想为什么? 其实 原数的因子就是 在(1, 2, 4), (1, 3), (1, 5, 25) 这三个集合中各挑一个,然后相乘,就可以形成一个因子。
因此一共会有3 * 2 * 3种挑选方法,亦即3*2*3个因子。
我刚开始思考的时候,是想用dp的方法计算这些因子中,各个余数的数量,然后求和。这么做显然会超时。 其实就是原来的
括号内先求和 ,再相乘。就等同于把括号打开后计算乘法后再相加。
5、快速幂算法:
这个我不想多说了,这次居然又写错一次,还另外溢出WA了一次:
ll pow(ll a, ll b) {
ll result = 1;
while (b > 0) {
if (b % 2 == 1) {
result = result * a % mod;
}
b /= 2;
a = a * a % mod; //这里要写对!!而且要加上mod
}
return result;
}
提交记录:
1、WA。因为没有考虑最后大于sqrt(n)的那
一个素因子。
2、WA。素因子分解的时候,循环条件应该是tmp != 1,而不是tmp != 0。因此这里只有可以整除的时候才会调用/, 所以不会除到0.
3、WA。每一次计算出来的result,都要去%mod,否则
可能溢出。
4、WA。快速幂中德a = a * a 一定要改为a = a * a % mod ,否则
会溢出。
5、WA。在计算cal中,减去的时pow(a, b+1),这里粗心了,写成了pow(a, b).
6、WA。为了保险,
最后结果如果为负数的时候,要先加上一个mod,再模除一下。
7、AC