Codeforces Round #828 (Div. 3)E1 + E2. Divisible Numbers (数学+思维)

173 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。

题目E1
题目E2

image.png
中文大意

给我们a,b,c,da,b,c,d四个整数选择两个数x,yx,y (a<x<=c,b<y<=d)(a<x<=c,b<y<=d)并且(xy)(x*y)%(ab)==0(a*b)==0E1和E2的差别就是a,b,c,d的范围不一样

E1解法

因为我们需要找到两个数x,yx,y但是由于数据范围所以我们先固定一个数然后去找另一个数。
为了让(xy)(x*y)%(ab)==0(a*b)==0我们可以想到如果是(nSmM)(n*S*m*M)%(ab)==0(a*b)==0是最好的,并且(ab)(a*b)%(SM)==0(S*M)==0这样我们就可以知道SMS*M肯定是a*b的因数,所以这题我们就可以化简为一题求因数的题目。 所以在我们枚举x时我们找出k=gcd(ab,x) k = gcd(a*b,x)这样其实我们就求出了一个S所以对于这个S我们也可以求出M,这样的话M=ab/kM = a * b / k这样就可以保证我们现在的kMk*M肯定是aba*b的倍数所以这样我们现在就可以求出最小M的整数倍是否在题目要求的范围内即可

void solve()
{
   int a,b,c,d; cin >> a >> b >> c >> d;
   int k = a * b;
   for(int i = a + 1; i <= c;i++) {
       int m = __gcd(k,i);
       m = k / m;
       int j = d / m * m;
       if(j > b && j <= d) {
         cout << i << ' ' << j << endl;
         return;
       }
   }
   cout << -1 << ' ' << -1 << endl;   
}

E2解法

对于E2由于数的范围到了1e91e9所以如果我们直接遍历的话是会超时的所有我们需要换一种写法。通过E1我们推导出了几个式子中得知我们可以先求出aba*b的因子然后我们可以先求出nmn*m的最小整数倍然后求出SMSM的最小整数倍是否在数据范围内即可。但是我们发现如果是直接求aba*b的因数我们是会超时的,因为a和b的数据范围都到了1e9,然后我们可以想到一个数字的因子数其实是很小的,这样我们可以先分别求出a和b的因子数遍历组合数a*b的所有因子数

   //先分别求出a,b的因子数
   int n = 0, m = 0;
   for(int i = 1; i * i <= a; i++) {
      if(a % i == 0) {
      x[++n] = i;
      if(i * i != a) x[++n] = a / i;         
   }
   }
   for(int i = 1; i * i <= b; i++) {
      if(b % i == 0) {
      y[++m] = i;
      if(i * i != b) y[++m] = b / i;         
      }

   }
   rep(i,n) rep(j,m) { //遍历组合出a*b的所有因子
      int t = x[i] * y[j]; // a*b的因子
      int k = a * b / t; //求出了 k = n * m 
      int l = ((a / t ) + 1)* t;//因为不可能等于本身所以加一
      int r = ((b / k ) + 1)* k;
      if(l > a && l <= c && r > b && r <= d) {
         cout << l << ' ' << r << endl;
         return;
      }
   }
   cout << -1 << ' ' << -1 << endl;