本文主要是介绍CCF CSP题解:因子化简(202312-2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
链接和思路
OJ链接:传送门。
问题重述
本题基于一个基本事实,即任何一个大整数 n n n都可以唯一地分解为如下形式
n = p 1 t 1 × p 2 t 2 × ⋯ × p m t m n = p_1^{t_1} \times p_2^{t_2} \times \cdots \times p_m^{t_m} n=p1t1×p2t2×⋯×pmtm其中, p 1 , p 2 , ⋯ , p m p_1, p_2, \cdots, p_m p1,p2,⋯,pm表示 m m m个素因子,素因子上的幂 t i > 0 ( 1 ≤ i ≤ m ) t_i > 0 (1 \le i \le m) ti>0(1≤i≤m)。
本题给出 q q q组 n , k n,k n,k,满足 1 < n ≤ 1 0 10 , 1 < k , q ≤ 10 1 < n \le 10^{10}, 1 < k, q \le 10 1<n≤1010,1<k,q≤10,要求对每组 n , k n,k n,k,求出 n n n除以所有满足 t i < k t_i<k ti<k的 p i t i p_i^{t_i} piti后的结果,即求出
n ∏ 1 ≤ i ≤ m 且 t i < k p i t i = ∏ 1 ≤ i ≤ m 且 t i ≥ k p i t i \frac{n}{\prod_{1 \le i \le m 且 t_i<k}p_i^{t_i}} = \prod_{1 \le i \le m 且 t_i \ge k}p_i^{t_i} ∏1≤i≤m且ti<kpitin=1≤i≤m且ti≥k∏piti
求解思路
由于 n n n较大,求出小于 n n n的所有的素数是很困难的。因此,我们考虑使用素数筛先求出 1 0 5 10^5 105以内的所有素数。如果出现有 p i > 1 0 5 p_i>10^5 pi>105的情况,则对应的 t i t_i ti必不可能大于1,只能等于1,且这样的 p i p_i pi最多只可能有1个。常见的素数筛有埃氏筛、欧拉筛等。本文使用埃氏筛,其实现如下:
static vector<long long> primes;
// 埃拉托斯特尼筛法,时间复杂度为O(n * loglogn)
void Find_Prime_number(long long n = N){vector<bool> flag(n + 1, true);//0和1不是素数,直接初始化好flag[0] = 0;flag[1] = 0;//从2开始,1不是素数for (long long i = 2; i <= n; i++){//如果当前数字是素数if (flag[i]){//i的倍数标记被不是素数for (long long j = i * i; j <= n; j += i)flag[j] = false;primes.push_back(i);}}
}
我们将素数筛获得的所有的 1 0 5 10^5 105以内的素数保存在vector<long long> primes
中。然后,将 n n n依次尝试除以primes
中的每个质因子 p i p_i pi。如果能够整除 p i p_i pi的次数大于等于 k k k,则说明 p i p_i pi是“重要的”,因此恢复到尝试除以 p i p_i pi之前的值。遍历完primes
后,我们再处理可能存在的大于 1 0 5 10^5 105的质因子。
上文提到,如果存在 p i > 1 0 5 p_i > 10^5 pi>105,在本题的设定中,最多只可能有1个,且对应的 t i t_i ti只可能为1,由于 k > 1 = t i k>1=t_i k>1=ti,最终答案要剔除掉 p i t i p_i ^{t_i} piti。
因此,我们需要引入如下函数,用以辅助判断 n n n除以 ∏ 1 ≤ i ≤ m 且 p i ≤ 1 0 5 p i t i \prod_{1 \le i \le m 且 p_i \le 10^5}p_i^{t_i} ∏1≤i≤m且pi≤105piti后,是否是一个大于 1 0 5 10^5 105素数。如果是,最终结果应该除以这个素数。
bool is_prime(long long n){for (long long i = 2; i * i <= n; i++)if(n % i == 0)return false;return true;
}
AC代码
满分代码如下,使用CPP 11标准即可编译运行。
#include <iostream>
#include <vector>
using namespace std;const long long N = 1e5+5;static vector<long long> primes;// 埃拉托斯特尼筛法,时间复杂度为O(n * loglogn)
void Find_Prime_number(long long n = N){vector<bool> flag(n + 1, true);//0和1不是素数,直接初始化好flag[0] = 0;flag[1] = 0;//从2开始,1不是素数for (long long i = 2; i <= n; i++){//如果当前数字是素数if (flag[i]){//i的倍数标记被不是素数for (long long j = i * i; j <= n; j += i)flag[j] = false;primes.push_back(i);}}
}bool is_prime(long long n){for (long long i = 2; i * i <= n; i++)if(n % i == 0)return false;return true;
}int main() {Find_Prime_number();int q;cin >> q;while(q--) {long long n;int k;cin >> n >> k;long long flag = n;for (long long prime: primes) {long long tmp = n;int cnt = 0;while (n % prime == 0){n /= prime;flag /= prime;cnt++;}if (cnt >= k) // 如果t_i足够大,说明不需要除以p_in = tmp; // 恢复}if (flag > N && is_prime(flag)){// 如果存在大于N的质因子p_i,其对应的t_i=1<k,需要去除n /= flag;}cout << n << endl;}return 0;
}
这篇关于CCF CSP题解:因子化简(202312-2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!