[HAOI2012]外星人
题目描述
艾莉欧在她的被子上发现了一个数字 N N N,她觉得只要找出最小的 x x x 使得, φ x ( N ) = 1 \varphi^x(N) = 1 φx(N)=1。根据这个 x x x 她就能找到曾经绑架她的外星人的线索了。当然,她是不会去算,请你帮助她算出最小的 x x x。
输入格式
第一行一个正整数 t e s t \mathrm{test} test,接下来 t e s t \mathrm{test} test 组数据每组数据第一行一个正整数 m m m,接下来 m m m 行每行两个正整数 p i , q i p_i, q_i pi,qi
其中 ∏ i = 1 m p i q i \displaystyle \prod_{i = 1}^{m} p_i^{q_i} i=1∏mpiqi 为 N N N 的标准分解形式。
∏ \prod ∏ 为连乘
φ x ( N ) \varphi^x(N) φx(N) 表示嵌套 x x x 次,不是幂
输出格式
输出 t e s t \mathrm{test} test 行,每行一个整数,表示答案。
样例 #1
样例输入 #1
1
2
2 2
3 1
样例输出 #1
3
提示
30 % 30\% 30% 的数据, N ≤ 1 0 6 N \le 10^6 N≤106。
60 % 60\% 60% 的数据, x ≤ 100 x \le 100 x≤100。
100 % 100\% 100% 的数据, t e s t ≤ 50 \mathrm{test} \le 50 test≤50, 1 ≤ p i ≤ 10 5 1 \le p_i \le {10}^5 1≤pi≤105, 1 ≤ q i ≤ 10 9 1 \le q_i \le {10}^9 1≤qi≤109, m ≤ 2000 m \le 2000 m≤2000。
φ \varphi φ 为欧拉函数, φ ( n ) \varphi(n) φ(n) 即小于等于 n n n 的数中与 n n n 互质的数的个数。
提示: φ ( ∏ i = 1 m p i q i ) = ∏ i = 1 m ( p i − 1 ) ∗ p i q i − 1 \varphi(\prod_{i=1}^mp_i^{q_i})=\prod_{i=1}^m(p_i-1)*p_i^{q_i-1} φ(∏i=1mpiqi)=∏i=1m(pi−1)∗piqi−1。
1、 素数的大小 <= 10^5, 直接用线性筛法打素数表
2、 题目给出的提示, 假如 p, q 都是素数, phi(p^n * q^m) = (p - 1)*p^(n - 1) * (q - 1) *q^(m - 1)
如果 p 是奇素数(p != 2), p - 1 必然含有 素因子2。 每一个奇数素数 减1, 再做素因子分解,
也必然含有 素因子2。 所以这道题跟素因子 2 有关。
3、 观察 n = p1^a1 * p2^a2 * … * pk^ak,
现在单独拿出一个素因子 pj 来考虑, pj - 1 也做素因子分解, 分解出好多素因子(假如有一个是 k),
k - 1 也要做素因子分解, …, 一直进行下去,都会分解出 素因子 2。
现在考虑的是,一个奇素数,做这样的操作,一共能搞出多少个2?
factor_2[p] 表示 素数减1, p - 1, 一直分解,最后能得到多少个2
显然 p - 1 = x * y (x, y 都是素数) ,那么
factor_2[p] = factor_2[x] + factor_2[y]
5、 每做一次欧拉函数的运算,素因子2就减少一个。
4、数组int factor_2[MaxN] 求出来后,题目就好解决了。 累加结果就行。
注意,如果一开始没有素因子2, 最后的结果要加1
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int MaxN = 100010;
const int MaxM = 2010;
int prime[MaxN], m;
int v[MaxN]; // v[i] 表示 i 包含的最小的素因子
bool vis[MaxN];
int factor_2[MaxN]; // factor_2[13] 表示 13 - 1 = 12 = 2^2 * 3 , 3 - 1 = 2^1 , 素因子减 1, 然后再因式分解,
// 最后能得到 3 个 素因子2
int T, M;
int p[MaxM], q[MaxM];
void factor_2_init()
{
factor_2[2] = 1;
for (int i = 2; i <= m; ++i)
{
int p = prime[i] - 1;
int cnt = 0, tmp = 0;
for (int j = 1; prime[j] <= sqrt(p); ++j)
{
if (p % prime[j] == 0)
{
tmp = 0;
while (p % prime[j] == 0)
{
++tmp;
p /= prime[j];
}
cnt += factor_2[prime[j]] * tmp;
}
}
tmp = 0;
if (p > 1) // 如果此时p 大于1, 说明p还是个素数
{
cnt += factor_2[p];
}
factor_2[prime[i]] = cnt;
}
}
void prime_init()
{
int n = MaxN - 10;
m = 0; //素数的个数
for (int i = 2; i <= n; ++i)
{
if (v[i] == 0)
{
v[i] = i; prime[++m] = i;
}
for (int j = 1; j <= m; ++j)
{
if (prime[j] > v[i] || prime[j] > n / i)
break;
v[i * prime[j]] = prime[j];
}
}
}
int main()
{
prime_init();
factor_2_init();
scanf("%d", &T);
while (T--)
{
scanf("%d", &M);
long long ans = 0;
for (int i = 1; i <= M; ++i)
{
scanf("%d%d", &p[i], &q[i]);
ans += factor_2[p[i]] * q[i];
}
if (p[1] != 2)
ans++;
printf("%lld\n", ans);
}
return 0;
}
/*
1
2
2 2
3 1
*/
/*
3
*/

该博客介绍了如何利用欧拉函数和素因子分解解决一道关于寻找最小x使得φx(N)=1的问题。博客内容涉及算法竞赛题目[HAOI2012]外星人,讲解了输入输出格式,并提供了样例。博主分析了素数表的构建、欧拉函数的性质,特别是对于奇素数如何通过素因子分解产生2的个数,以及如何计算最终结果。解决方案包括计算素因子2的数量并累加,特别指出没有素因子2的情况需额外处理。
8870

被折叠的 条评论
为什么被折叠?



