UVA10837
由唯一分解定理:
n
=
∏
i
=
1
k
(
p
i
a
i
)
n=\prod\limits_{i=1}^{k}(p_i^{a_i})
n=i=1∏k(piai)
由欧拉函数定义:
ϕ
(
n
)
=
n
∏
i
=
1
k
(
1
−
1
p
i
)
=
∏
i
=
1
k
(
p
i
a
i
)
∏
i
=
1
k
(
1
−
1
p
i
)
=
∏
i
=
1
k
(
p
i
−
1
)
p
i
a
i
−
1
\phi(n)\\=n\prod\limits_{i=1}^{k}(1-\frac{1}{p_i})\\=\prod\limits_{i=1}^{k}(p_i^{a_i})\prod\limits_{i=1}^{k}(1-\frac{1}{p_i})\\=\prod\limits_{i=1}^{k}(p_i-1)p_i^{a_i-1}
ϕ(n)=ni=1∏k(1−pi1)=i=1∏k(piai)i=1∏k(1−pi1)=i=1∏k(pi−1)piai−1
因此,对于给定的
ϕ
(
n
)
\phi(n)
ϕ(n),我们可以将所有符合条件
m
m
o
d
(
p
i
−
1
)
=
=
0
m\mod (p_i-1)==0
mmod(pi−1)==0的素数筛选出来,然后再枚举选取多个
p
i
p_i
pi即可。
但由于素数表只打到10000以内的素数,即
p
h
i
n
\sqrt {phi_n}
phin。不过由于大于
p
h
i
n
\sqrt {phi_n}
phin的素数至多有一个,所以在特判即可。
因为最后一个素数的范围为
[
2
,
p
h
i
n
]
[2,phi_n]
[2,phin],因此只要这个数与
[
2
,
p
h
i
n
]
[2,\sqrt{phi_n}]
[2,phin]内的所有数互质,那么它就是素数。
以下函数为判断最后一个选取的素数。
inline bool Judgt(const int& Remainder) {
//遍历素数表,判断最后剩下的是否为素数
for (int i = 0; i < PrimeTable.size(); ++i) {
const int& prime = PrimeTable[i];
if (Remainder % prime == 0) {
return false;
}
if (prime * prime > Remainder) {
break;
}
}
//返回是否未选过
return Used.find(Remainder) == Used.end();
}
完整代码:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
#include <unordered_set>
using namespace std;
int m;
bool IsNotPrime[10001];
vector<int> PrimeTable;
vector<int> Candidates;
unordered_set<int> Used;
void InitPrimeTable() {
for (int i = 2; i <= 10000; ++i) {
if (IsNotPrime[i] == false) {
PrimeTable.push_back(i);
for (int j = i * i; j <= 10000; j += i) {
IsNotPrime[j] = true;
}
}
}
}
void InitCandidates() {
for (int i = 0; i < PrimeTable.size(); ++i) {
const int& prime = PrimeTable[i];
if (m % (prime - 1) == 0) {
Candidates.push_back(prime);
}
if ((prime - 1) * (prime - 1) > m) {
break;
}
}
}
int Ans;
inline bool Judgt(const int& Remainder) {
for (int i = 0; i < PrimeTable.size(); ++i) {
const int& prime = PrimeTable[i];
if (Remainder % prime == 0) {
return false;
}
if (prime * prime > Remainder) {
break;
}
}
return Used.find(Remainder) == Used.end();
}
void DFS(int Index = 0, int Remainder = m, int n = 1) {
if (Index == Candidates.size()) {
if (Remainder == 1) {
Ans = min(Ans, n);
}
else if (Judgt(Remainder + 1)) {
n *= (Remainder + 1);
Ans = min(Ans, n);
}
return;
}
DFS(Index + 1, Remainder, n);
const int& CurPrime = Candidates[Index];
if (Remainder % (CurPrime - 1)) {
return;
}
Used.insert(CurPrime);
Remainder /= (CurPrime - 1);
n *= CurPrime;
DFS(Index + 1, Remainder, n);
while (Remainder % CurPrime == 0) {
Remainder /= CurPrime;
n *= CurPrime;
DFS(Index + 1, Remainder, n);
}
Used.erase(CurPrime);
}
void InitData() {
Ans = 200000000;
Candidates.clear();
Used.clear();
}
int main() {
InitPrimeTable();
int Case = 0;
while (~scanf("%d", &m) && m) {
InitData();
InitCandidates();
DFS();
printf("Case %d: %d %d\n", ++Case, m, Ans);
}
return 0;
}