目录
今天带来5个比较简单的数论题,就今年蓝桥JavaC组能出7/9两个数论而言,国赛必定数论!!!
第一题:连续因子
题目初步解析:
假定一个数n,可以分解成a*b*c*d=n;
若最长为3,那么需要满足n%(a*b*c)=0或者n%(b*c*d)=0;
当我们需要一个连续长为x的值,起始值为a
那么就要有:n%(a*(a+1)*(a+2)*......*(a+x))=0
那么我们在每一次判断的时候就可以进行一个当前累乘值大小进行计算
满足条件即当前长度是可行的,不然就是当前长度无法满足
通过样例进行深一步讲解:
样例:630=3*5*6*7;
因为题目说明不包括1,所以从2开始计算
假设T为累乘的值,T=2,630%2=0,满足,长度为1
T=6,630%6=0,满足,此时长度更改为2;
T=24,630%24!=0,不满足条件,也就是说三个数暂时无法满足
那么我们把最前面的那个数去除,即T=3*4=12;
这时,我们不需要去判断630%12是否为0,因为现在也是2个长度,我们直接往后计算即可
T=60,630%60!=0,T=20;
T=120,630%120!=0,T=30;
T=210,630%210=0,此时长度为3,更新当前的左端点为5即可;
然后继续计算T=210*8=1680>n,即可退出判断
输出当前长度X,然后从左端点起输出X个数
完整代码:
import java.util.Scanner;
public class 连续因子 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
long n=sc.nextLong();
long k= (long) Math.sqrt(n);
long sum=1;//乘积总值
long count=0;//记录长度
long l=2;//记录当前左端点
long x=2;//记录第一个值
for (int i=2;i<=k;i++){
sum*=i;
if (n%sum!=0){//不满足条件
sum/=l;//去除最左边的数
if (i-l>count){//新的长度
count=i-l;//更改长度
x=l;//更改左端点
}
l++;//更新最左边的数
}
if (sum>n){
break;
}
}
if (count==0){
System.out.println(1);
System.out.println(n);
return;
}
System.out.println(count);
System.out.print(x);
for (int i=1;i<count;i++){
System.out.print("*"+(x+i));
}
}
}
第二题:最小正整数
题目初步解析:
给定两个数A,B,求最小的一个拥有B个的A的倍数
假设B=5,那么这个数的最小值为100000,然后又要求这个数是A的倍数,且为100000的倍数
所以这题实际上相当于求1后面B个0下,A与其的最小公倍数
通过样例进一步讲解:
A=375,B=4;
那么最小的值为X=10000;
所以求375和10000的最小公倍数;
求最小公倍数的话我们可以通过求最大公因数
然后通过a/最大公因数*X即可得到最小值
例如A=375,B=4,即X=10000;
gcd(375,10000)=125;
Min=375/125*10000=30000;
完整代码:
import java.util.Scanner;
public class 最小正整数 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int T=sc.nextInt();
while (T-->0){//T组
Long n=sc.nextLong();
int k=sc.nextInt();
long s=1;
for (int i=1;i<=k;i++){//求出最小的有k个0的数
s*=10;
}
long m=n/gcd(n,s);
System.out.println(m*s);
}
}
public static long gcd(long a, long b){//求最大公因数
if (b==0){
return a;
}else{
return gcd(b,a%b);
}
}
}
第三题:约数之和
完整代码:
import java.util.Scanner;
public class 约数之和 {
static int mod=9901;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int a=sc.nextInt();
int b=sc.nextInt();
if (a==0){
System.out.println(0);
return;
}
if (a==1||b==0){
System.out.println(1);
return;
}
long res=1;
for (long i=2;i<=a;i++){
int k=0;
while (a%i==0){
k++;
a/=i;
}
k=k*b;
res = res * (ksm(i, k + 1, mod * (i - 1)) - 1) / (i - 1) % mod;
}
System.out.println(res);
}
static long ksm(long a,long b,long c){
long res = 1;
while (b>0){
if ((b&1)==1){
res=res*a%c;
}
a=a*a%c;
b=b>>1;
}
return res % c;
}
}
第四题:最大公约数
原题链接
欧拉函数,只过了13/14,最后一个超时
完整代码:
import java.util.Scanner;
public class 最大公约数 {
static Scanner sc=new Scanner(System.in);
static int n=sc.nextInt();
static boolean []st=new boolean[n+1];
static int []arr=new int[n+1];
static int []brr=new int[n+1];
static int count=0;
static long []crr=new long[n+1];
public static void main(String[] args) {
init(n);
long sum=0;
for (int i=0;i<count;i++) sum+=crr[n/arr[i]]*2+1;
System.out.println(sum);
}
static void init(int n){
for(int i=2;i<=n;i++) {
if(!st[i]) {
arr[count++]=i;
brr[i] = i-1;
}
for(int j =0;arr[j]*i<=n;j++) {
st[arr[j]*i]=true;
if(i%arr[j]==0) {
brr[i*arr[j]] = brr[i]*arr[j];
break;
}
brr[i*arr[j]] = brr[i]*(arr[j]-1);
}
}
for(int i =1;i<=n;i++) crr[i]=crr[i-1]+brr[i];
}
}
第五题:记事本
题目初步解析:
给定一个n,需要从1个复制到n个
那么我们可以知道,如果需要通过连续x次粘贴某一个长度,那么这个长度必须是n的因子
例如:n=4,那么可以连续粘贴1或者连续粘贴2,不能通过3粘贴3;
所以我们可以先去计算出该n的因子有哪些,然后运算到达每一个因子时的最短次数即可
通过例子进一步讲解:
例如n=12,
那么会存在6个因子:arr[0]=1,arr[1]=2,arr[2]=3;arr[3]=4,arr[4]=6,arr[5]=12;
因为初始是有1个的,所以brr[0]=0;
那么需要多少次才能到达arr[1],我们只需要计算arr[1]的因子有哪些,到达它的因子需要的次数
比如2的因子是1和2,除去本身只有1,那么它就是由1复制后粘贴1次,那么brr[1]=2
同理,brr[2]=3;
当arr[3]=4,4的因子有1和2,那么可以通过1复制粘贴3次获得,也可以通过2复制粘贴获得
取最小方案的值,即4次
brr[3]=4;
brr[4]=brr[2]+2+1=5,也可以是brr[4]=brr[3]+1+1=5
brr[5]=brr[0]+1+11=12;
brr[5]=brr[1]+1+5=8;
brr[5]=brr[2]+1+3=7;
brr[5]=brr[3]+1+2=7;
brr[5]=brr[4]+1+1=7;
取最小值为7,所以到12个需要7次(注意,复制也算一次,所以每一次都有个+1);
完整代码:
import java.util.Arrays;
import java.util.Scanner;
public class 记事本 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int x= (int) Math.sqrt(n);
int []arr=new int[n];
int count=0;//计算因子个数
int s=1,sum=1;
for (int i=1;i<=x;i++){//进行因子存放
if (n%i==0){
arr[count]=i;
count++;
if (n/i!=i){
arr[count]=n/i;
count++;.
}
}
}
Arrays.sort(arr,0,count);
int [][]brr=new int[count][2];
brr[0][0]=1;
brr[0][1]=0;
for (int i=1;i<count;i++){//每一个因子需要多少次才能到
brr[i][0]=arr[i];
brr[i][1]=9999999;
for (int j=0;j<i;j++){//因子只可能是比它小,并且是n的因子
if (brr[i][0]%arr[j]==0){
brr[i][1]=Math.min(brr[i][0]/arr[j]+brr[j][1],brr[i][1]);
}
}
}
System.out.println(brr[count-1][1]);
}
}