CCF刷题计划——因子化简
计算机软件能力认证考试系统
我的蒟蒻暴力法:
很暴力的算法,但是过了。主要就是想着将所有的素数都先dia出来,然后将n对每一个素数都进行一次相爱相杀,同时记录用上的素数和指数。顺便学了个素数筛,之所以把全部素数都提前弄出来,其实就是为了防止多次重复计算素数。其实看到范围限制的时候就可以放弃这个策略了,因为全部的测试数据满足:1<n<=1e10 且 1<k,q≤10,相当于最多只重复个10次而已。
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
const long long N=1e8;
#define ll long longll n;
int k,q;vector<bool>statue(N,true); //存放,是否为素数,默认全为素数
vector<int>primes;void getVec(vector<pair<int,int>>&vec,ll n)
{for(int i=0;i<primes.size();i++){int a=primes[i];int b=0;if(n%a==0){while(n%a==0) //如果是倍数{n/=a;b++;}vec.push_back({a,b}); //将素数和指数加进去 }}
}//欧拉筛,还是现学的
void euler_sieve() //这里使用欧拉筛将所有的素数罗列
{statue[0]=statue[1]=false; //默认0,1都不是素数for(ll i=2;i<=N;i++) //从2到N遍历一遍{if(statue[i]) //如果当前是素数primes.push_back(i); //存起来 for(ll j=0;j<primes.size();j++) //不论是不是素数,都要将该数i和素数集都乘一次{if(i*primes[j]>N) break; //如果超出标记范围,就跳出 statue[i*primes[j]]=false; //标记合数 if(i%primes[j]==0) break; //如果标记到最小素倍数(i是primes[j])那就溜啦//这一步是为了不重复标记 } }
}int main()
{cin>>q;euler_sieve();while(q--){cin>>n>>k;ll div=1;vector<pair<int,int>>vec;getVec(vec,n);for(int i=0;i<vec.size();i++){if(vec[i].second<k) //逆向,除去 div*=pow(vec[i].first,vec[i].second);}cout<<n/div<<endl; }return 0;
}
下面是另一篇题解[CCF-CSP——因子化简)
他没有用欧拉筛选出所有的素数,而是在遍历过程中判断是否为素数,相当于而言减少很多不必要的计算。但是借此机会学习我上面提到的欧拉筛也是一桩美事~
#include<bits/stdc++.h>
using namespace std;//判断素数
int isPrime(int x) {for (int i = 2; i * i <= x; i++) {if (x % i == 0) {return 0;}}return 1;
}void query(long long n, int k) {long long temp = n;long long final = 1;for(int i=2; i * i <= n; i++) {if(isPrime(i)){int num = 0;while(n%i==0){n/=i; num++;}
// printf("%d\n", num);if(num>=k){while(num--){final*=i;}}}}if(final==temp){printf("%lld\n", temp);}else if(final==1){printf("1\n");}else{printf("%lld\n", final);}
}int main() {int q;scanf("%d", &q);for(int i=0; i<q; i++) {long long n;int k;scanf("%lld%d", &n, &k);query(n, k);}return 0;
}