【 51NOD 1434 素数筛 】【数论+思维+筛素数】区间LCM【找到一个最小整数M,满足M>N,LCM(N+1,N+2,..,M-1,M)是LCM(1,2,3,4,.,N-1,N) 的倍数】

传送门:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1434

思路:

虽然是四级题,但是思路还是不太清晰,找网上题解讲的很多不是特别清晰(可以随便举些例子理解一下)

首先可以得出一个性质:LCM(1,2,3,4,...,N-1,N) 中质因子k的出现的次数为t,则有k^t<=n

根据这个性质我们先筛出素数,然后枚举每个质数,求出对应的k和t,然后找出倍数j(不会很大),使得j*k^t>n,这个j*k^t是ans的可能取值,所以ans = max(ans, j*k^t)不断更新最大的ans,这样可以保证尽量小的m使得LCM(N+1,N+2,....,M-1,M)中存在j*k^t把LCM(1,2,3,4,...,N-1,N)k^t除尽

代码:

(个人觉得这个代码结合上面的题解容易理解些)

#include <bits/stdc++.h>
using  namespace  std;

template<class T> T sqr(T x){ return x * x; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}

const int N=1e6+10;

int n;
int prime[N];

void init(){
  for(int i = 2; i * i < N; i++)if(!prime[i]){
    for(int j = 2 * i; j < N; j += i)prime[j] = 1;
  }
}

int  main(){
  int T;
  read(T);
  init();
  while(T--){
    read(n);
    int ans = 2, num;
    for(int i = 2; i <= n; i++)if(!prime[i]){//素数
      int u = (int)(log(n) / log(i));
      int v = (int)pow(i, u);
      for (int j = 2; ; ++j)if (v * j > n){
        v *= j;
        break;
      }
      ans = max(ans, v);
    }
    printf("%d\n", ans);
  }
  return 0;
}

网上的题解:

假设有质数K,可以求出t,使得K的t次方刚好小于等于m(K^t<=m)那么lcm(1,2,…,m)分解质因数中一定而且最多有t个质数K连乘,其实我们可以就是求的质数的最高次幂,这样就可以很快地吧lcm(1,2,…,m)分解质因数那么怎么把 lcm(n+1,n+2,…,m)分解质因数呢仍然假设质数K,可以求出最大的t,以及一个常数c(1<=c < K),使得 n+1<=c*K^t<=m
那么lcm(n+1,n+2,…,m)分解质因数中一定而且最多有t个质数K连乘。比如说质数3,n=16,m=22,可以求的c=2,t=2,即17<=2*3^2=18<=22,这样lcm(17,18,19,20,21,22)中最多有2个质数3连乘既然知道怎么求lcm(n+1,n+2,..,m)和lcm(1,2,..,m)了来探讨一下怎么求最小的m吧我们想让这两个lcm分解质因数后完全一样,也就是说连乘的质数个数也完全相等。也就是说,对于每个质数K都可以满足,存在c和最大的t 使得n+1<=c*K^t<=m对于大于n小于m的质数,我们假设是P,那么一定n+1<=P<=m,一定可以满足条件所以我们就只看小于等于n的质数就可以了因为要使每个小于N的质数K,都存在c和最大的t 使得n+1<=c*K^t<=m,我们枚举每一个质数,并求得c和t,使得刚好c*K^t>=n,
答案就取最大的c*K^t,即 max( c*K^t )这样lcm(1,2,…,m)和lcm(n+1,n+2,…,m)的分解质因数后均至少有t个质数K。如果最终m有 k^(t+1)<=m,那么这个K^(t+1)>n一定成立,故仍满足条件

代码:

#include <bits/stdc++.h>
using  namespace  std;

template<class T> T sqr(T x){ return x * x; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}

const int N=1e6+10;

int n;
int prime[N];

void init(){
  for(int i = 2; i * i < N; i++)if(!prime[i]){
    for(int j = 2 * i; j < N; j += i)prime[j] = 1;
  }
}

int  main(){
  int T;
  read(T);
  init();
  while(T--){
    read(n);
    int ans = 2, num;
    for(int i = 2; i <= n; i++)if(!prime[i]){//素数
      for(num = i; num <= n/i; num *= i)  ;

      ans = max(ans, (n / num + 1) * num);  
    }
    printf("%d\n", ans);
  }
  return 0;
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值