https://blog.csdn.net/fxt275307894a/article/details/109449321?utm_medium=distribute.pc_relevant.none-task-blog-title-2&spm=1001.2101.3001.4242
这个是老哥的题解,搜了好多,就老哥这个看懂了。
改写了一点点,希望老哥不要介意
题意:输入n,再输入n对x,y。对于每一对x,y,找到一个数m,使得x%m==0 && m%y!=0 ;并且m要最大
改写是进行了分类
1.x<y, x 本身满足
2.x==y, x除以x的最小质因数,使得x2<y并且最大(x2=x/x的最小质因数)
3.x>y
- x%y!=0,即x不是y的倍数,x本身满足
2)x%y==0
就是
假如b里面有p个ai,a里面有k个ai,因为a是b的因数,所以k>=p,只要让a2里面只剩p-1个ai,则必有a2%b!=0
此时a2=a/(ai ^ ( ww ) )
p-1=k-ww
(去掉ww个ai)
#include<cstdio>
#include<cmath>
#include<map>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,z,f[100039],s[100039],d[100039],head,dh,t,sh;
map<long long,int> q;
long long x,y,now,tot,pus,ans,flag;
int main(){
// freopen("1.in","r",stdin);
register int i,j;
for(i=2; i*i<=1e9; i++) {
if(!f[i]) s[++head]=i;//s[i]为质数
for(j=1; j<=head&&i*s[j]<=100000; j++) {
f[i*s[j]]=1;
if(i%s[j]==0) break;
}
}
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&x,&y);now=y;
if(x<y||x%y)
{
printf("%lld\n",x);
continue;
}
if(x==y){
for(i=1;s[i]<=x&&i<=head;i++)
if(x%s[i]==0){
x/=s[i];
break;
}
printf("%lld\n",x);
continue;
}
dh=0;pus=1e18;
for(i=1;s[i]*s[i]<=y&&i<=head;i++){
if(now%s[i]==0){
d[++dh]=s[i];//y的质因数列表
while(now%s[i]==0)q[s[i]]++,now/=s[i];
}
}
if(now!=1)q[now]++,d[++dh]=now;//最后一个质因数大于根号y的情况
//大于根号y的因数只可能有一个
//小于等于根号y的数从now中剔除完之后就只剩大于根号y的因数或者一
//这里是一个优化,要找到那个质因数在for循环里可能还需要需要许多步骤,而这里只要一步
now=x;
for(i=1;i<=dh;i++){
if(x%d[i]==0){//从y的质数列表来考虑
ans=0;
while(x%d[i]==0) x/=d[i],ans++;
tot=1;
for(j=1;j<=ans-q[d[i]]+1;j++) tot*=d[i];
pus=min(pus,tot);
}
}
printf("%lld\n",now/pus);//
q.clear();
}
}