总感觉这题在去年湖南多校里见过
题意:
题目给了你一个等式,给出你a,b,问是否有满足条件的c,d,e,f
思路:
其实感觉这种题,一定和约数有关,不然你枚举不了。
正解是对b质因数分解,分出两个互质的数,分别赋个d和f,那么可以得到等式 d ∗ e − c ∗ f = a d*e-c*f=a d∗e−c∗f=a,这对应了扩展欧几里得方程,且两个系数互质,这保证了一定有解。解出一组合理解即可。
如果b和a不互质的话,可以直接分解输出。
如果 b b b和 a a a互质,且 b b b没有大于2个的素因子,那么无解。
证明为:将 b b b分解为 p k p^k pk, b b b和 a a a互质,则左边的数通分约分后一定分别等于 a , b a,b a,b。但是左边的分子对素数 p p p的指数都小于 k k k,所以通分约分后不可能得出包含 p k p^k pk因子的分子,所以无解。
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef long long ll;
const int maxn = 2e6 + 7;
vector<ll>Div;
ll gcd(ll n,ll m) {
return m == 0 ? n : gcd(m,n % m);
}
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);
ll z = x;x = y;y = z - a / b * y;
return d;
}
int prime[maxn],b[maxn],v[maxn],cnt;
void getprime() {
for(int i = 2;i < maxn;i++) {
if(v[i] == 0) {
v[i] = i;prime[++cnt] = i;
}
for(int j = 1;j <= cnt && i * prime[j] < maxn;j++) {
v[i * prime[j]] = prime[j];
if(i % prime[j] == 0)break;
}
}
}
int main() {
getprime();
int T;scanf("%d",&T);
while(T--) {
ll a,b;scanf("%lld%lld",&a,&b);
ll Gcd = gcd(a,b);
if(Gcd != 1) {
printf("%lld %lld %lld %lld\n",a * 2 / Gcd,b / Gcd,a / Gcd,b / Gcd);
continue;
}
if(v[b] == b || b == 1) {
printf("-1 -1 -1 -1\n");
continue;
}
ll c = -1,d = -1,e = -1,f = -1;
for(int i = 1;i <= cnt && prime[i] <= b;i++) {
ll num = 1,tmp = b;
while(tmp % prime[i] == 0) {
tmp /= prime[i];
num *= prime[i];
f = num;
}
if(num != 1) {
f = num;d = b / num;
break;
}
}
if(f == b) {
printf("-1 -1 -1 -1\n");
continue;
}
ll D = exgcd(f,d,c,e);
c = a / D * c;
e = a / D * e;
ll mod1 = d / D,mod2 = f / D;
ll k1 = 0,k2 = 0;
if(c <= 0) {
k1 = max(k1,-c / mod1 + 1);
}
if(e >= 0) {
k2 = max(k2,e / mod2 + 1);
}
c += max(k1,k2) * mod1;
e -= max(k1,k2) * mod2;
printf("%lld %lld %lld %lld\n",c,d,-e,f);
}
return 0;
}