CPAIR - Editorial

PROBLEM LINK:

Practice
Space Travel

Author: ultimate_st
Tester: chef_oggy
Editorialist: ultimate_st

DIFFICULTY:

MEDIUM

PROBLEM:

Given a pair of integers (a, b) which represents a message, and the message can be decoded by finding the value of x (x>0) that must be added to both a and b in order to make them non-coprime.

Prerequisites:

  • Sieve
  • A pinch of mathematics :smile:

Hint

Since a,b \leq 10^6 you will precompute a sieve of smallest prime factors and you have to obtain factorization in O(log n).

QUICK EXPLANATION:

The problem is about decoding messages represented by pairs of integers (a, b), where the values of a and b need to be modified by adding a positive integer x to both of them to make them non-coprime. We can solve this problem by implementing a prime factorization algorithm using the sieve of Eratosthenes and finding the minimum value of x required to make a and b non-coprime. It can be done by finding the prime factors of the difference between a and b, and then finding the minimum value of x that satisfies the condition by checking each factor. If the absolute difference between a and b is 1, then the code outputs -1 since it is impossible to make them non-coprime by adding a positive integer.

EXPLANATION:

We know that the gcd of two numbers divides their difference. Therefore, if we compute the difference d between a and b, then any common divisor of a+x and b+x must also divide d. Therefore, we can factorize d by precomputing sieve before test cases loop. Then we can factorize d in O(log d) time.

For each prime factor p[i] , we calculate the remainder of a divided by p[i]. This is done to find the smallest integer k such that a + k is divisible by p[i] . We then subtract a%p[i] from p[i] to get the difference between a and the nearest multiple of p[i] that is greater than a . This gives us the value of k that satisfies the condition that a+k is divisible by p[i] . We take the minimum of min and this value of k for all prime factors p[i] of d . The resulting value of min is the minimum value of x that satisfies the condition that a+x and b+x are non-coprime.

For computing factorization using sieve ,we create an array spf of size 10^6+1, where spf[i] represents the smallest prime factor of i. We start by initializing spf[1] as 1, as 1 is not a prime number. We then mark the smallest prime factor of every number i to be itself, i.e. spf[i] = i. We then mark the smallest prime factor of every even number to be 2.

Next, we loop through every odd number from 3 to sqrt(n) and check if it is a prime number by checking if spf[i] == i. If i is a prime number, we mark the smallest prime factor of all its multiples as i, unless it has already been marked as a smaller prime factor. This way, we calculate the smallest prime factor of every number in the range from 1 to n.

The getFactorization method takes a number x as input and returns a vector containing the prime factorization of x. We start by dividing x by its smallest prime factor, which we can find using the spf array. We then keep dividing x by its smallest prime factor until we can no longer do so. We add each smallest prime factor to a vector and return the vector once we have completely factorized x.
The time complexity of getFactorization method will be O(log n) and that of sieve will be O(nloglogn).

SOLUTIONS:

Setter's Solution
/* package codechef; // don't place package name! */

import java.util.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */

class cac
{
   static final int MAXN = 1000001;

   static int spf[] = new int[MAXN];

   static void sieve()
   {
       spf[1] = 1;
       for (int i=2; i<MAXN; i++)
           spf[i] = i;

       for (int i=4; i<MAXN; i+=2)
           spf[i] = 2;
     
       for (int i=3; i*i<MAXN; i++)
       {
           if (spf[i] == i)
           {
               for (int j=i*i; j<MAXN; j+=i){
                   if (spf[j]==j)
                       spf[j] = i;
               }
           }
       }
   }
   static ArrayList<Integer> getFactorization(int x)
   {
       ArrayList<Integer> ret = new ArrayList<>();
       while (x != 1)
       {
           ret.add(spf[x]);
           x = x / spf[x];
       }
       return ret;
   }
   public static void main (String[] args) throws java.lang.Exception
   {
   	// your code goes here
   	FastReader sc=new FastReader();
   	int t=sc.nextInt();
       sieve(); //precomputation
       
   	ab:while(t-->0){
           int a=sc.nextInt();
           int b=sc.nextInt();
           if(Math.abs(a-b)==1){
               System.out.print(-1+"\n");
               continue ab;
           }
           int d=Math.abs(b-a);
           ArrayList<Integer> p = getFactorization(d);
           int min=Integer.MAX_VALUE;
           for (int i=0; i<p.size(); i++)
               {
                   min=Math.min(min,p.get(i)-(a%p.get(i)));
               }
           System.out.println(min);
       }
   }
}

class FastReader {

       BufferedReader br;
       StringTokenizer st;
       public FastReader() {
           br = new BufferedReader(new InputStreamReader(System.in));
       }
       String next() {
           while (st == null || !st.hasMoreElements()) {
               try {
                   st = new StringTokenizer(br.readLine());
               }
               catch (IOException e) {
                   e.printStackTrace();
               }
           }
           return st.nextToken();
       }
       int nextInt() {
           return Integer.parseInt(next());
       }
       long nextLong() {
           return Long.parseLong(next());
       }
       double nextDouble() {
           return Double.parseDouble(next());
       }
       String nextLine() {
           String str = "";
           try {
               str = br.readLine();
           }
           catch (IOException e) {
               e.printStackTrace();
           }
           return str;
       }
}
Tester's Solution
                       //The more you know, the more you don't know//
#include <bits/stdc++.h> 

#define loop(i,m,n) for(ll i=m;i<n;i++)
#define rev(i,m,n) for(ll i=m;i>=n;i--)
#define ll long long
#define in(n) cin>>n
#define out(n) cout<<n<<"\n"
#define o(n) cout<<n<<" "
#define nl cout<<"\n"
#define yes cout<<"YES"<<"\n"
#define no cout<<"NO"<<"\n"
#define pb push_back
#define ppb pop_back
#define size(x) x.size()
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define MAX(x) *max_element(all(x))
#define MIN(x) *min_element(all(x))
#define SUM(x) accumulate(all(x), 0LL)
#define SORT(x) is_sorted(all(x))
#define lcm(x,y) (x*y)/__gcd(x,y)
#define dgt(n) floor(log10(n)+1)
#define point cout<<fixed<<setprecision(10)
#define debug(x) cout<<#x<<" "<<x<<"\n";
#define print(v) for(auto x : v)  o(x);  nl; 
#define ub(v,val) upper_bound(all(v),val)-v.begin()
#define lb(v,val) lower_bound(all(v),val)-v.begin()
const long long M = 1e9 + 7;
const long long inf = LONG_LONG_MAX;

using namespace std; 

//--------------------[...Never Used Functions...]---------------------//
ll binpow(ll a, ll b){   ll res=1;      while(b>0){     if(b&1) res=res*a;    a=a*a; b>>=1;    }       return res;     }
ll powmod(ll a, ll b, ll m) {ll ans = 1; while (b) {if (b & 1) {ans = (ans * a) % m;} a = (a * a) % m; b = b >> 1;} return ans % m;}
vector<ll> div(ll n){   vector<ll> v;   for(int i=1; i<=sqrt(n); i++){     if (n%i == 0){   v.pb(i);    if(n/i!=i) v.pb(n/i);  }   }   return v;   }
vector<ll> primediv(ll n){  vector<ll> v;   for(ll i=2;i<=sqrt(n);i++){   while(n%i==0){ n=n/i; v.pb(i); }  }   if(n>1) v.pb(n);    return v;   }
ll modINV(ll n,ll mod){      return powmod(n,mod-2,mod);    }
ll ncrmod(ll n,ll r,ll p){  if(r==0)     return 1;   unsigned long long fac[n + 1]={1};  for(int i=1;i<=n;i++)    fac[i]=(fac[i-1]*i)%p;  return (((fac[n]*modINV(fac[r],p))%p)*modINV(fac[n-r],p))%p;  }
double logg(ll n,ll k){   return log2(n)/log2(k);   }
//---------------------------------------------------------------------//

/*------------------------[...DSU...]------------------------//
ll parent[100007];   ll Size[100007];
void make(ll v){   parent[v]=v;    Size[v]=1;  }
ll find(ll v){    if(v==parent[v])    return v;       return parent[v] = find(parent[v]);     }
void Union(ll a,ll b){   a = find(a);    b = find(b);    if(a!=b){   if(Size[a] < Size[b])   swap(a,b);      parent[b] = a;      Size[a] += Size[b];     }      }
//----------------------------------------------------------*/

#define MAXN   1000001
int spf[MAXN];

void sieve()
{
   spf[1] = 1;
   for (int i=2; i<MAXN; i++)
       spf[i] = i;

   for (int i=4; i<MAXN; i+=2)
       spf[i] = 2;

   for (int i=3; i*i<MAXN; i++)
   {
       if (spf[i] == i)
       {
           for (int j=i*i; j<MAXN; j+=i)
               if (spf[j]==j)
                   spf[j] = i;
       }
   }
}

vector<int> getFactorization(int x)
{
   vector<int> ret;
   while (x != 1)
   {
       ret.push_back(spf[x]);
       x = x / spf[x];
   }
   return ret;
}

void drizzle()
{
   ll a,b;     in(a>>b);

   if(min(a,b)==max(a,b)-1)
   {
       out(-1);
   }
   else
   {
       if(a%2==b%2)
       {
           if(b&1)     out(1);
           else
           {
               if(__gcd(a+1,b+1)!=1)       out(1);
               else        out(2);
           }
       }
       else
       {
           ll n=max(a,b)-min(a,b);
           vector<int> factors = getFactorization(n);

           ll res=inf;
           for(auto x : factors)
           {
               res=min(res,x-(min(a,b)%x));
           }

           if(res==inf)    out(n);
           else            out(res);
       }
   }

   return;
}

int main()
{
   ios_base::sync_with_stdio(false);       
   cin.tie(nullptr);         
   cout.tie(nullptr);
   
   int testcase=1;     
   cin>>testcase;

   sieve();

   while(testcase--)
   {
       drizzle();
   }

   return 0;
}