我来提供一个非常暴力的做法
显然,我们只需要考虑P是Q的倍数的情况。
在这种情况下
我们考虑对q的质因数分解
为
p
1
n
1
∗
p
2
n
2
∗
p
3
n
3
.
.
.
p
n
n
n
p_1^{n_1}*p_2^{n_2}*p_3^{n_3}...p_n^{n_n}
p1n1∗p2n2∗p3n3...pnnn
然后对于每一个
p
1
p_1
p1考虑
使得P不断除以
p
1
p_1
p1,直到P不能整除Q为止,记录此时的P。
以12 和6 为例
6
=
2
1
∗
3
1
6 = 2^1*3^1
6=21∗31
首先对2考虑
12
/
2
/
2
=
3
c
a
n
′
t
d
i
v
6
12/2/2=3 \ can't \ div \ 6
12/2/2=3 can′t div 6
再对3考虑
12
/
3
=
4
c
a
n
′
t
d
i
v
6
12/3 =4 \ can't \ div \ 6
12/3=4 can′t div 6
那么答案就是
m
a
x
(
3
,
4
)
=
4
max(3,4)=4
max(3,4)=4
众所周知,质因数分解的代码为
unordered_map<long long,int>ooo;
for(register ll i=2;i<=n/2;i++){
while(n!=i){
if(n%i==0){
ooo[i]++;//质因数为i的数量
n=n/i;
}
else
break;
}
}
if(n>1){
ooo[n]++;
}
正常情况下,其平均复杂度为O(n^(1/4))
但在n为质数的情况下,复杂度会被卡成O(n)
然后我就被卡了
显然P<=1e9,
假如P给定50个998344353那就直接当场去世
然后我们就要考虑处理这种情况下的优化
那我们加一层素数判断?
is_prime();//判断素数
unordered_map<long long,int>ooo;
for(register ll i=2;i<=n/2;i++){
while(n!=i){
if(n%i==0){
ooo[i]++;//质因数为i的数量
n=n/i;
}
else
break;
}
}
if(n>1){
ooo[n]++;
}
然而给定50个998244353*2一定会被卡。
最后,我们选用欧拉筛进行优化
,也就是先对欧拉筛的质因数先进行一个预处理。
然后,对预处理之后的数再进行判断质数+质因数分解。
这样,我们就能写成
map<long long,int>mp;
int prime[N];
int visit[N];
int cnt=0;
void Prime(){
for (int i = 2;i <= N; i++) {
if (!visit[i]) {
prime[++cnt] = i;//纪录素数
}
for (int j = 1; j <=prime[0] && i*prime[j] <= N; j++) {
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
void solve(ll n){
Prime();//欧拉筛
for(int i=1;i<=cnt;i++)//先用欧拉筛里的素数进行预处理
{
while(n%prime[cnt]==0)
{
n/=prime[cnt];
}
}
if(n==1)return ;
if(is_prime(n)){//判断素数
mp[n]++;
return ;
}
for(register ll i=prime[cnt];i<=n/2;i++){
while(n!=i){
if(n%i==0){
mp[i]++;
n=n/i;
}
else
break;
}
}
if(n>1){
mp[n]++;
}
}
bool is_prime(int x){
if(x==1)
return false;
if(x==2||x==3)
return true;
if(x%6!=1&&x%6!=5)
return false;
int s=sqrt(x);
for(int i=5;i<=s;i+=6)
if(x%i==0||x%(i+2)==0)
return false;
return true;
}
设原本要进行质因数分解的数为N
设预处理的最大质数为M(可近似看成质数数量*10~15)
那么时间复杂度最坏情况下为
O
(
N
M
+
N
M
1
/
2
)
,
常
数
很
小
O(\frac N M+{\frac N M}^{1/2}),常数很小
O(MN+MN1/2),常数很小
或者
O
(
N
1
/
2
)
O(N^{1/2})
O(N1/2)
在
∑
N
<
=
1
0
16
\sum N<= 10^{16}
∑N<=1016的情况下均可保证在1s内。
原题AC代码,没必要用欧拉筛,暴力筛即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 10000
unordered_map<long long,int>ooo;
inline bool is_prime(int x){
if(x==1)
return false;
if(x==2||x==3)
return true;
if(x%6!=1&&x%6!=5)
return false;
int s=sqrt(x);
for(register int i=5;i<=s;i+=6)
if(x%i==0||x%(i+2)==0)
return false;
return true;
}
inline void ok(ll n){
/*可以写成欧拉筛,这里没有必要,因为N太小*/
while(n%2==0){
n/=2;
ooo[2]++;
}
while(n%3==0){
n/=3;
ooo[3]++;
}
while(n%5==0){
n/=5;
ooo[5]++;
}
while(n%7==0){
n/=7;
ooo[7]++;
}
while(n%11==0){
n/=11;
ooo[11]++;
}
if(n==1)return ;
if(is_prime(n)){
ooo[n]++;
return ;
}
for(register ll i=11;i<=n/2;i++){
while(n!=i){
if(n%i==0){
ooo[i]++;
n=n/i;
}
else
break;
}
}
if(n>1){
ooo[n]++;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ooo.clear();
ll p,q;
scanf("%lld%lld",&p,&q);
if(p<q||p%q!=0||p==1){
cout<<p<<endl;
continue;
}
ll ans = 0;
ok(q);
for(auto iter = ooo.begin(); iter != ooo.end(); iter++)
{
ll tp=p,tq=q;
while(tp%tq==0){
tp/=(iter->first);
}
ans = max(ans,tp);
}
cout<<ans<<endl;
}
}
当 ∑ N < = 1 0 16 \sum N<= 10^{16} ∑N<=1016考虑下面的代码(可AC)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 1000000
unordered_map<long long,int>ooo;
int prime[N];
int visit[N];
int cnt=0;
inline void Prime(){
for (int i = 2;i <= N; i++) {
if (!visit[i]) {
prime[++cnt] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数
}
for (int j = 1; j <=prime[0] && i*prime[j] <= N; j++) {
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
inline bool is_prime(int x){
if(x==1)
return false;
if(x==2||x==3)
return true;
if(x%6!=1&&x%6!=5)
return false;
int s=sqrt(x);
for(register int i=5;i<=s;i+=6)
if(x%i==0||x%(i+2)==0)
return false;
return true;
}
inline void ok(ll n){
/*可用欧拉筛优化,这里没有必要*/
Prime();//欧拉筛
for(int i=1;i<=cnt;i++)
{
while(n%prime[cnt]==0)
{
n/=prime[cnt];
}
}
if(n==1)return ;
if(is_prime(n)){
ooo[n]++;
return ;
}
for(register ll i=2;i<=n/2;i++){
while(n!=i){
if(n%i==0){
ooo[i]++;
n=n/i;
}
else
break;
}
}
if(n>1){
ooo[n]++;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ooo.clear();
ll p,q;
scanf("%lld%lld",&p,&q);
if(p<q||p%q!=0||p==1){
cout<<p<<endl;
continue;
}
ll ans = 0;
ok(q);
for(auto iter = ooo.begin(); iter != ooo.end(); iter++)
{
ll tp=p,tq=q;
while(tp%tq==0){
tp/=(iter->first);
}
ans = max(ans,tp);
}
cout<<ans<<endl;
}
}