描述
Xiaoming has just come up with a new way for encryption, by calculating the key from a publicly viewable number in the following way:
Let the public key N = A^B, where 1 <= A, B <= 1000000, and a0, a1, a2, …, ak-1 be the factors of N, then the private key M is calculated by summing the cube of number of factors of all ais. For example, if A is 2 and B is 3, then N = A^B = 8, a0 = 1, a1 = 2, a2 = 4, a3 = 8, so the value of M is 1 + 8 + 27 + 64 = 100.
However, contrary to what Xiaoming believes, this encryption scheme is extremely vulnerable. Can you write a program to prove it?
输入
There are multiple test cases in the input file.
Each test case starts with two integers A, and B. (1 <= A, B <= 1000000). Input ends with End-of-File.
输出
For each test case, output the value of M (mod 10007) in the format as indicated in the sample output.
提示
2008 Asia Hangzhou Regional Contest Online.
分析
给定A,B,求
N
=
A
B
N=A^B
N=AB的各个因子的因子个数的立方和。比较拗口,用公式叙述。设N的因子为
a
1
,
a
2
,
.
.
.
,
a
k
a_1,a_2,...,a_k
a1,a2,...,ak,对于任意
a
i
(
1
≤
i
≤
k
)
a_i (1\leq i\leq k)
ai(1≤i≤k),求
a
i
a_i
ai的因子个数 ,然后求得最终结果
M
=
∑
i
=
0
k
n
M=\sum_{i=0}^{k}n
M=∑i=0kn,输出结果取余10007。
定义1:函数
d
(
a
)
d(a)
d(a)是
a
a
a的因子个数。例如,4的因子个数为3个,分别是1,2,4,则
d
(
4
)
=
3
d(4)=3
d(4)=3。
定义2:函数
D
(
N
)
D(N)
D(N)是
N
N
N的各个因子的立方和,即
D
(
N
)
=
∑
m
∣
N
m
3
D(N)=\sum_{m|N}m^3
D(N)=∑m∣Nm3。
引理1:
d
(
a
)
d(a)
d(a)和
D
(
N
)
D(N)
D(N)是积性函数(multiplicative function)。事实上两者是除数函数(divisor function)的两种特殊情况,而除数函数是积性函数。积性函数
f
(
x
)
f(x)
f(x)具有如下性质:
(1)
f
(
1
)
=
1
f(1)=1
f(1)=1
(2)
f
(
a
⋅
b
)
=
f
(
a
)
⋅
f
(
b
)
f(a\cdot b)=f(a)\cdot f(b)
f(a⋅b)=f(a)⋅f(b),当且仅当a,b互质
满足上面两条性质,那么我们说
f
(
x
)
f(x)
f(x)是积性函数。
引理2:积性函数的除数函数还是积性函数。
证明(可略过):
{
假设
f
(
x
)
f(x)
f(x)是积性函数,令
D
(
f
)
D(f)
D(f)为
f
f
f的除数函数。假设
(
m
,
n
)
=
1
(m,n)=1
(m,n)=1(即m,n互质),则有:
[
D
(
f
)
]
(
m
)
=
∑
a
∣
m
f
(
a
)
a
n
d
[
D
(
f
)
]
(
n
)
=
∑
b
∣
n
f
(
b
)
[D(f)](m)=\sum_{a|m}f(a) \quad and \quad [D(f)](n)=\sum_{b|n}f(b)
[D(f)](m)=a∣m∑f(a)and[D(f)](n)=b∣n∑f(b)
即:
[
D
(
f
)
]
(
m
)
⋅
[
D
(
f
)
]
(
n
)
=
(
∑
a
∣
m
f
(
a
)
)
(
∑
b
∣
n
f
(
b
)
)
=
∑
a
∣
m
∑
b
∣
n
f
(
a
)
f
(
b
)
[D(f)](m)\cdot [D(f)](n)=\left( \sum_{a|m}f(a)\right)\left( \sum_{b|n}f(b)\right) =\sum_{a|m} \sum_{b|n} f(a)f(b)
[D(f)](m)⋅[D(f)](n)=⎝⎛a∣m∑f(a)⎠⎞⎝⎛b∣n∑f(b)⎠⎞=a∣m∑b∣n∑f(a)f(b)
由于
(
m
,
n
)
=
1
(m,n)=1
(m,n)=1,
a
∣
m
a|m
a∣m,
b
∣
n
b|n
b∣n,故
(
a
,
b
)
=
1
(a,b)=1
(a,b)=1(证明略,高代基础)。因此由
f
(
x
)
f(x)
f(x)为积性函数可得:
[
D
(
f
)
]
(
m
)
⋅
[
D
(
f
)
]
(
n
)
=
∑
a
∣
m
∑
b
∣
n
f
(
a
b
)
[D(f)](m)\cdot [D(f)](n)=\sum_{a|m} \sum_{b|n} f(ab)
[D(f)](m)⋅[D(f)](n)=a∣m∑b∣n∑f(ab)
对于
m
n
mn
mn的任意一个因子,我们都可以将其写作
d
=
a
b
d=ab
d=ab其中
a
∣
m
a|m
a∣m且
b
∣
n
b|n
b∣n。故:
[
D
(
f
)
]
(
m
)
⋅
[
D
(
f
)
]
(
n
)
=
[
D
(
f
)
]
(
m
⋅
n
)
[D(f)](m)\cdot [D(f)](n)=[D(f)](m\cdot n)
[D(f)](m)⋅[D(f)](n)=[D(f)](m⋅n)
得证
D
(
f
)
D(f)
D(f)为积性函数。
参考:
http://sites.millersville.edu/bikenaga/number-theory/divisor-functions/divisor-functions.html
}
正式解题:
题目要我们求的其实就是
[
D
(
d
)
]
(
N
)
=
∑
a
∣
N
d
(
a
)
[D(d)](N)=\sum_{a|N}d(a)
[D(d)](N)=∑a∣Nd(a),
d
(
a
)
d(a)
d(a)是a的因子个数。由引理2可知该函数为积性函数,且
N
=
A
B
N=A^B
N=AB,由于积性函数应用的前提条件是两个数互质,故不妨先将
A
A
A拆解为素数乘积形式:
A
=
∏
i
=
1
k
p
i
r
i
A=\prod_{i=1}^k p_i^{r_i}
A=i=1∏kpiri
其中
k
k
k为
A
A
A素数分解后的项数,
p
i
p_i
pi为素数,
r
i
r_i
ri为
p
i
p_i
pi出现的次数。
例如:
20
=
2
2
⋅
5
1
20=2^2\cdot 5^1
20=22⋅51。
那么对于
N
=
A
B
N=A^B
N=AB,就有:
N
=
A
B
=
∏
i
=
1
k
p
i
r
i
B
N=A^B=\prod_{i=1}^k p_i^{r_iB}
N=AB=i=1∏kpiriB
由于
B
B
B是对
A
A
A的整体次幂,故直接落于每个质因子上。由于乘积的每一项都是素数的次幂,故每一项对于其他项都是互质的,可以使用积性函数的特性,有:
[
D
(
d
)
]
(
N
)
=
[
D
(
d
)
]
(
A
B
)
=
[
D
(
d
)
]
(
∏
i
=
1
k
p
i
r
i
B
)
=
∏
i
=
1
k
[
D
(
d
)
]
(
p
i
r
i
B
)
=
∏
i
=
1
k
∑
(
d
(
p
i
r
i
B
)
)
3
[D(d)](N)=[D(d)](A^B)\\ =[D(d)]\left( \prod_{i=1}^k p_i^{r_iB}\right)\\ =\prod_{i=1}^k[D(d)]\left(p_i^{r_iB}\right)\\ =\prod_{i=1}^k\sum \left(d\left(p_i^{r_iB}\right)\right)^3
[D(d)](N)=[D(d)](AB)=[D(d)](i=1∏kpiriB)=i=1∏k[D(d)](piriB)=i=1∏k∑(d(piriB))3
每一个等号都是一次变换,我把过程尽量细化了,还看不太懂的话可以往上面翻一翻。
还记得
[
D
(
d
)
]
[D(d)]
[D(d)]的定义吗?先求变量的各个因子,再求每一个因子的因子的个数。
由于
p
i
r
i
B
p_i^{r_iB}
piriB是素数次幂的形式,故其因子序列为
p
i
0
,
p
i
1
,
…
,
p
i
r
i
B
,
p_i^0,p_i^1,\dots ,p_i^{r_iB},
pi0,pi1,…,piriB,共
r
i
B
+
1
r_iB+1
riB+1项。
而每一项作为素数
p
i
p_i
pi的
k
k
k次幂,其因子个数必然为
k
+
1
k+1
k+1项,即
d
(
p
i
k
)
=
k
+
1
d\left( p_i^k\right)=k+1
d(pik)=k+1,故最终结果:
[
D
(
d
)
]
(
N
)
=
∏
i
=
1
k
(
∑
j
=
1
r
i
B
+
1
j
3
)
[D(d)](N)=\prod_{i=1}^k\left( \sum_{j=1}^{r_iB+1}j^3\right)
[D(d)](N)=i=1∏k(j=1∑riB+1j3)
又由于简单的立方和公式,故有:
[
D
(
d
)
]
(
N
)
=
∏
i
=
1
k
(
(
r
i
B
+
1
)
×
(
r
i
B
+
1
+
1
)
2
)
2
[D(d)](N)=\prod_{i=1}^k\left( \frac{\left(r_iB+1\right)\times\left(r_iB+1+1\right)}{2}\right)^2
[D(d)](N)=i=1∏k(2(riB+1)×(riB+1+1))2
故,只需要求出
A
A
A的素数分解,得到每一个素数因子出现的次数
r
i
r_i
ri,就可以解出来这道题目了!
我求素数分解的方式是线性素数筛,时间复杂度
O
(
n
)
O(n)
O(n),具体原理可以百度。
java代码
/**
* @Author weizhiwei
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class Main {
static int mod = 10007;
public static void main(String[] args) throws IOException{
InputReader in = new InputReader(System.in);
ArrayList<Integer> prime = Prime.solve(1000000);
int ts = 1;
while(in.hasNext()) {
long A = in.nextInt();
long B = in.nextInt();
ArrayList<Integer> r = new ArrayList<>();
for(int i = 0; i < prime.size() && A>1; i++) {
int pr = prime.get(i);
if(A%pr==0) {
int cnt = 0;
while(A%pr==0) {
A/=pr;
cnt++;
}
r.add(cnt);//即文字叙述中的ri,每一个素数项的指数
}
}
long ans = 1;
for(int ri:r) {
long n = ri*B+1;
long tmp = (n*(n+1))/2 % mod;//立方和的一部分
tmp *= tmp;//立方和
tmp %= mod;
ans *= tmp;
ans %= mod;//每一项立方和的结果相乘
}
System.out.println("Case "+ts+": "+ans);
ts++;
}
}
//快速读入
static class InputReader{
StringTokenizer token;
BufferedReader bf;
InputReader(InputStream in){
token = null;
bf = new BufferedReader(new InputStreamReader(in));
}
String next(){
try{
while(token==null || !token.hasMoreTokens()){
token = new StringTokenizer(bf.readLine());
}
}catch(Exception e){}
return token.nextToken();
}
int nextInt(){
return Integer.parseInt(next());
}
boolean hasNext()
{
boolean result = false;
try {
result = bf.ready();
}catch (IOException e){
}
return result;
}
}
static class Prime {
/**
*
* @param n 范围为[1.n]
* @return [1,n]之间的所有素数
*/
public static ArrayList<Integer> solve(int n) {
ArrayList<Integer> ans = new ArrayList<>();
int[] isPrime = new int[n+10];
for(int i = 2; i <= n; i++) {
if(isPrime[i]==0) {
ans.add(i);
}
for(int p:ans) {
if(i*p>n)
break;
isPrime[i*p] = 1;//筛去
if(i%p==0)
break;
}
}
return ans;
}
}
}