题目大意:
给两个正整数a和b;
要求找到四个正整数c,d,e,f,满足 a b = c d − e f \frac{a}{b}=\frac{c}{d}-\frac{e}{f} ba=dc−fe
思路:
预处理
先init预处理出1到MAXN每个数字的最小质因子
第一种情况,如果 g c d ( a , b ) ≠ 1 gcd(a,b)\not = 1 gcd(a,b)=1
即a/b是可以化简的
直接有
a b = ⌊ a b ⌋ 1 − b − a b \frac{a}{b}=\frac{\lfloor \frac{a}{b} \rfloor}{1}-\frac{b-a}{b} ba=1⌊ba⌋−bb−a
这第一种情况是比较好理解的。
第二种情况
处理完第一种情况后,如果b只有一个或者没有真因子,如8,9,16,25之类的数字,则无解。
第三种情况
找到b的两个互质且相乘结果为b的因子:
因为之前预处理过每个数的最小真因子在yz[b]数组中,这个最小真因子显然一定是质的。
我们设d=yz[b],f=b/yz[b],使b=d*f得到满足
然后为了满足第二个条件d与f互质,根据唯一分解定理,我们只需要把f中所有的yz[b]都移动到d上即可。
d = yz[b];
f = b/yz[b];
while(f%yz[b]==0){//去除f中所有的yz[b]
d*=yz[b];//移动到d身上
f/=yz[b];
}
题目要求
a b = c d − e f \frac{a}{b}=\frac{c}{d}-\frac{e}{f} ba=dc−fe
合并两个分数
a b = c f − d e d f \frac{a}{b} = \frac{cf-de}{df} ba=dfcf−de
移项
d f b = c f − d e a \frac{df}{b} = \frac{cf-de}{a} bdf=acf−de
我们又知道df=b,所以左边可以变成1
1 = f ⋅ ( c a ) − d ⋅ ( e a ) 1 = f \cdot (\frac{c}{a}) - d \cdot (\frac{e}{a}) 1=f⋅(ac)−d⋅(ae)
设x=c/a;y=-e/a则有
1 = f ⋅ x + d ⋅ y 1 = f \cdot x + d \cdot y 1=f⋅x+d⋅y
这时候就可以想到我们可以用扩展欧几里得了
Exgcd(f,d,x,y);
while(x<=0||y>=0){//使x>0,y<0
x+=d;y-=f;
}
c = x*a; e = -y*a;
在得到x和y之后,我们要找到一组x>0且y<0的解。
有一组解怎么找其他解可以看这个帖子https://www.cnblogs.com/Antigonae/p/10106068.html
AC代码:
(是补的,比赛的时候我跟个傻X一样)
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
template<class T>inline void read(T &x){x=0;char o,f=1;while(o=getchar(),o<48)if(o==45)f=-f;do x=(x<<3)+(x<<1)+(o^48);while(o=getchar(),o>47);x*=f;}
//int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
//多谢cc0408大哥,之前我开了同步流还用printf,其实是有问题的,感谢大哥指出
#define ll long long
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repb(i,a,b) for(int i=(a);i>=b;i--)
#define INF 0x3f3f3f3f
#define cendl printf("\n")
ll gcd(ll a,ll b){ while(b^=a^=b^=a%=b); return a; }
//#define INF 0x7fffffff
ll Exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1;y=0;return a;}//边界条件结束递归
ll d = Exgcd(b,a%b,x,y);//gcd
ll t = x;
x=y;y=t-(a/b)*y;//通过x2y2求得x1y1,层层返回
return d;
}
const int MAXN = 2e6+5;
int yz[MAXN];
void init(){
int sqr = sqrt(MAXN);
rep(i,1,MAXN-1) yz[i] = 0;
for(int i=2;i<=sqr;i++){
if(yz[i])continue;
for(int j=2;i*j<MAXN;j++){
if(yz[i*j]==0) yz[i*j]=i;
}
}
}
ll a,b,c,d,e,f;
void solve(){
cin>>a>>b;
int gcdd = gcd(a,b);
a/=gcdd; b/=gcdd;
int qm = a/b;//把分数化成 qm + a/b的形式
a%=b;
if(gcdd!=1){//第一种情况
printf("%d %d %d %d\n",qm+1,1,b-a,b);
return;
}
if(!yz[b]){
printf("-1 -1 -1 -1\n");
return;
}
d = yz[b];
f = b/yz[b];
while(f%yz[b]==0){//去除f中所有的yz[b]
d*=yz[b];//移动到b身上
f/=yz[b];
}
if(f==1){printf("-1 -1 -1 -1\n");return;}//单个真因子的情况(第二种情况)
ll x,y;
Exgcd(f,d,x,y);
while(x<=0||y>=0){//使x>0,y<0
x+=d;y-=f;
}
c = x*a; e = -y*a;
printf("%lld %lld %lld %lld\n",qm*d+c,d,e,f);
}
int main(){
init();
int z;
cin>>z;
while(z--) solve();
}