合适数对
合适数对
给定一个长度为 的正整数数列 和一个正整数 。
请你判断共有多少个数对 同时满足:
- 存在一个整数 使得 成立
输入格式
第一行包含两个整数 。
第二行包含 个正整数 。
输出格式
一个整数,表示满足条件的数对的数量。
数据范围
前三个测试点满足 。
所有测试点满足 。
输入样例:
6 3 1 3 9 8 24 1
输出样例:
5
解题思路
这题需要用到算术基本定理。对于一个数,如果是次幂的话,那么就有,否则就至少存在一个,有。因此这道题目就是要任意找两个数和,使他们的乘积的所有质因子的次幂都满足,问有多少对这种数。
我们枚举,看前面有多少个使得满足条件。先把进行质因数分解,得到,由于我们只关心质因数的次数是否为的倍数,因此我们只需要关心质因数的次数模后是否等于。对于要找的,应该满足(这是对应质因子的次数相加,如果具有不同的质因子,那么另一个数对应的次幂应该等于,同样满足)。
由于每一个,我们可以估算一下一个数可以最多分解到多少个不同的质因数,有,因此可以发现每个数最多可以分解到个不同的质因子。因此每个数最多只有个质因子的次幂需要补充为的倍数。
对于,我们找到它分解质因数后所有次幂不是的倍数的质因子,假设为,假设这些质因子的次幂模后为,容易发现。对于,其质因数分解后与相对应的的次幂模后为,如果对于所有的都满足,那么这个就是我们要找的。补充:因为,,因此小于且能被整除的数就只有。
我们可以直接用次幂模后不为的质因子的乘积进行哈希,例如上面的,。
AC代码如下:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 typedef long long LL; 6 7 const int N = 1e5 + 10; 8 9 int cnt[N]; 10 11 LL power(int a, int b) { 12 LL ret = 1; 13 while (b--) { 14 ret *= a; 15 if (ret >= N) return 0; // 由于ai都满足<=1e5,因此大于1e5就没有意义了 16 } 17 return ret; 18 } 19 20 int main() { 21 int n, k; 22 scanf("%d %d", &n, &k); 23 24 LL ret = 0; 25 while (n--) { 26 int val; 27 scanf("%d", &val); 28 29 LL p = 1, q = 1; // p表示对aj来说,次幂模k后不为0的质因子的乘积;q表示对于要找的ai,次幂互补的质因子的乘积 30 for (int i = 2; i <= val / i; i++) { // 对aj分解质因数 31 int t = 0; 32 while (val % i == 0) { 33 t = (t + 1) % k; 34 val /= i; 35 } 36 37 if (t) { // 次幂不为0才需要相乘 38 p *= power(i, t); // i^t,累乘的结果必然不超过1e5 39 q *= power(i, k - t); // 相同质因子的次幂要互补,即i^(k-t),累乘的结果可能超过1e5 40 if (q >= N) q = 0; // 超过1e5就没有意义了,赋值为0 41 } 42 } 43 if (val > 1) { 44 p *= val; 45 q *= power(val, k - 1); 46 if (q >= N) q = 0; 47 } 48 49 ret += cnt[q]; 50 cnt[p]++; 51 } 52 53 printf("%lld", ret); 54 55 return 0; 56 }
上面的质因数分解的时间复杂度为。我们还可以用线性筛,因为线性筛可以得到每一个数的最小质因子,因此在分解质质因数时可以用最小质因子来进行分解,每一个数包含的质因子个数大约为个,因此这种方法的时间复杂度为的。
AC代码如下:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 typedef long long LL; 6 7 const int N = 1e5 + 10; 8 9 int primes[N], cnt, minp[N]; 10 bool vis[N]; 11 int mp[N]; 12 13 void get_prime(int n) { 14 for (int i = 2; i <= n; i++) { 15 if (!vis[i]) { 16 primes[cnt++] = i; 17 minp[i] = i; 18 } 19 for (int j = 0; primes[j] <= n / i; j++) { 20 vis[primes[j] * i] = true; 21 minp[primes[j] * i] = primes[j]; 22 if (i % primes[j] == 0) break; 23 } 24 } 25 } 26 27 LL power(int a, int b) { 28 LL ret = 1; 29 while (b--) { 30 ret *= a; 31 if (ret >= N) return 0; 32 } 33 return ret; 34 } 35 36 int main() { 37 int n, k; 38 scanf("%d %d", &n, &k); 39 40 get_prime(N); 41 42 LL ret = 0; 43 while (n--) { 44 int val; 45 scanf("%d", &val); 46 47 LL p = 1, q = 1; 48 while (val > 1) { 49 int t = minp[val], s = 0; 50 while (val % t == 0) { 51 s = (s + 1) % k; 52 val /= t; 53 } 54 55 p *= power(t, s); 56 if (s) q *= power(t, k - s); 57 if (q >= N) q = 0; 58 } 59 60 ret += mp[q]; 61 mp[p]++; 62 } 63 64 printf("%lld", ret); 65 66 return 0; 67 }
参考资料
AcWing 4319. 合适数对(AcWing杯 - 周赛):https://www.acwing.com/video/3751/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16062423.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探