[题解](gcd/lcm)luogu_P1072_Hankson的趣味题(NOIP2009)
连续三次不开longlong导致wa!!!
不开longlong一时爽,一会提交火葬场!!!
OI千万条,longlong第一条
乘法不longlong,提交两行泪
暴力luogu就能过了???打好暴力的重要性!!!(事实上只能拿90分)
1.暴力
根据lcm(x,b0)==b1可以发现x一定是b1的约数,所以枚举用试除法b1的约数,暴力判断是否符合条件
(数学题发现性质的重要性
复杂度O(n*sqrt(b1)*log(b1)),预处理出1~sqrt(2*1e9)的所有质数,用搜索组成d的所有约数,在判断是否满足可过
#include<bits/stdc++.h> #define ll long long using namespace std; ll aa,ba,ab,bb,ans; inline ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } inline ll lcm(ll a,ll b){ return a*b/gcd(a,b); } void div(ll n){ for(int i=1;i*i<=n;i++){ if(n%i==0){ ll g=gcd(i,aa),l=lcm(i,ba); if(g==ab && l==bb)ans++; if(n/i!=i){ ll g=gcd(n/i,aa),l=lcm(n/i,ba); if(g==ab && l==bb)ans++; } } } } int main(){int T; scanf("%d",&T); while(T--){ ans=0; scanf("%d%d%d%d",&aa,&ab,&ba,&bb); div(bb); printf("%lld\n",ans); } }
2.正解
因为x是b1的约数,所以x的质因子一定是b1的质因子。可以对b1的每个质因子p,计算x可能包含多少个p。
设a0,a1,b0,b1,x有质因子p个数为ma0,ma1,mb0,mb1,mx,mx未知
思考可以得出:
对于gcd(x,a0)=a1:
(1)若ma0>ma1,则mx只能等于ma1
(2)若ma0==ma1,则只需满足mx>=ma1
(3)若ma0<ma1,无解
对于lcm(x,b0)=b1:
(1)若mb0<mb1,mx只能等于mb1
(2)若mb0==mb1,只需满足mx<=mb1
(3)若mb0>mb1,无解
综合分类讨论(恶心),其他情况组合判断即可
对于ma0==ma1 && mb0==mb1的情况,只要保持在ma1<=mx<=mb1的范围内取值即可,共有md-mc+1种取法
每个质因子都是相对独立的,根据乘法原理,总取值即为每次的答案相乘。
预处理出1~sqrt(1e9)中的素数,若b1为质数,那么直接计算有质因子b1的个数即可
复杂度O(n*sqrt(b1)/ log(b1))
#include<bits/stdc++.h> #define ll long long using namespace std; //±©Á¦£º //ll aa,ba,ab,bb,ans; //inline ll gcd(ll a,ll b){ // return b?gcd(b,a%b):a; //} //inline ll lcm(ll a,ll b){ // return a*b/gcd(a,b); //} //void div(ll n){ // for(int i=1;i*i<=n;i++){ // if(n%i==0){ // ll g=gcd(i,aa),l=lcm(i,ba); // if(g==ab && l==bb)ans++; // if(n/i!=i){ // ll g=gcd(n/i,aa),l=lcm(n/i,ba); // if(g==ab && l==bb)ans++; // } // } // } //} //int main(){int T; // scanf("%d",&T); // while(T--){ // ans=0; // scanf("%d%d%d%d",&aa,&ab,&ba,&bb); // div(bb); // printf("%lld\n",ans); // } //} //Õý½â£º ll aa,ba,ab,bb,ans=1; int prime[10000],ck[50009],tot; inline void div(int p){ int ma0=0,ma1=0,mb0=0,mb1=0; while(aa%p==0){ma0++;aa/=p;} while(ab%p==0){ma1++;ab/=p;} while(ba%p==0){mb0++;ba/=p;} while(bb%p==0){mb1++;bb/=p;} if((ma0<ma1)||(mb0>mb1)) ans=0; else if((ma0==ma1)&&(mb0<mb1) || (ma0>ma1)&&(mb0==mb1)){ if(ma1>mb1)ans=0; } else if((ma0==ma1)&&(mb0==mb1)){ if(ma1<=mb1)ans*=(mb1-ma1+1); else ans=0; } else if((ma0>ma1)&&(mb0<mb1)){ if(ma1!=mb1)ans=0; } } int main(){ for(int i=2;i<=50000;i++){ if(!ck[i])prime[++tot]=i; for(int j=1;j<tot;j++){ if(i*prime[j]>50000)break; ck[i*prime[j]]=1; if(i%prime[j]==0)break; } } int T; scanf("%d",&T); while(T--){ ans=1; scanf("%d%d%d%d",&aa,&ab,&ba,&bb); for(int i=1;i<=tot;i++){ div(prime[i]); if(ans==0)break; } if(bb>1)div(bb);//²»È»»áwaÒ»¸öµã printf("%lld\n",ans); } }