数论例题讲解

本文介绍了数论中的基础题目,包括分数分解、天才的约数和、反素数的概念及其性质,以及除法表达式的解题思路。每个问题都给出了相应的解题方法,并涉及质因数分解、约数和验证、反素数的性质以及贪心策略的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本周刚开始学习数论,直接被虐爆。。
下面是几道基础题目的题解。

1。分数分解
这里写图片描述
这里需要一个转换:
1/x+1/y=1/n到xy=nx+ny到n*n=(x-n)(y-n);
转化到这一步,我们就知道了满足条件的方法数等于n*n的因子数(包括1和n*n)除以二.
代码:

#include<bits/stdc++.h>
using namespace std;
int n,ans=1;
int main()
{
    scanf("%d",&n);
    int k;
    for(int i=2;i*i<=n;++i)
      {
        for(k=0;n%i==0;++k)
          n/=i;
        ans*=k*2+1;
      }
    if (n>1) ans*=3;
    printf("%d",ans/2);
    return 0;
}

这里求因子的方法不可以用暴力,要分解质因数,用乘法原理求因子数。

——————————————————

2.天才的约数和
这里写图片描述

这里有一个定理:某个数的约数倒数之和*这个数=这个数的约数和。
但是这题不能直接用这个公式,因为有些时候这个公式算出来的结果是不对的,所以要验证。
为什么不对呢。
例如,题目给出 18 9 5 那我们一算,这个数是10. 验证一下10的约数1,2,5,10,加起来刚好等于18,所以正确。但是如果题目给的是 36 18 5 算出来的也是10,但是10的约数和是18而不是36,这就是要验证的原因。
代码:

#include<bits/stdc++.h>
using namespace std;
long long a,b,c;
bool check(int x)
{
    long long sum=1;
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0) sum+=x/i+i;  if(i*i==x) sum--;
    }
    if(x>1) sum+=x; if(sum==a) return 1; else return 0;
}
int main()
{
    while(1)
    {
        cin>>a>>b>>c;
        if(a==0) exit(0);
        if(a*c%b!=0) 
        cout<<0<<endl,exit(0);  
        if(check(a*c/b))    cout<<1<<" "<<a*c/b<<endl;
        else    cout<<0<<endl;
    }
    return 0;
}

—————————————————
3.反素数
这里写图片描述
这题真的毒瘤。。
反素数就是从1到这个数之间每个数的约数个数都比这个数要小。
所以这道题就是求1到n这件最大的反素数。
要注意反素数满足一个性质。
如果把反素数质因数分解,质数从小到大排,每个质数的指数是不上升的。
根据这个就可以虚伪乱搜索了。
代码:

#include<bits/stdc++.h>
using namespace std;
int p[30]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 
int n,ans=-1,maxn=-1;
void dfs(long long m,int f,int t,int k) //这个数,素数表第几个,约数个数,指数 
{
   if(t>maxn||(t==maxn&&m<ans))
   ans=m,maxn=t;
   int j=0,net; long long nm=m;
   while(j<k)
   {
     j++;
     if(n/nm<p[f]) break;
     net=t*(j+1);
     nm=nm*p[f];
     if(nm<=n) dfs(nm,f+1,net,j);
   }
}
int main()
{
    scanf("%d",&n);
    dfs(1,1,1,30);
    printf("%d",ans);
    return 0;
} 

——————————————————
4.除法表达式
这里写图片描述

这题要结合贪心思想。
其实你会发现除了第二个数,其他所有数都可以通过括号划分到分子或分母,为了能够尽量能整除,我们就把除了第二个数以外所有的数都放到分子中,这样整除的几率是最大的,这就是我们的贪心策略。每当一个数加入分子时,就分子分母同时除去他和分母的gcd,如果分母变成1,那就代表整除了。
代码:

#include<bits/stdc++.h>
using namespace std;
long long a[100001],t=0,q=0,len,lc,sum,num,lc2,cl;
char str[100011];
int  gcd(int a,int b)
{
    if(!b) return a;
    return gcd(b,a%b);
}
int main()
{
  scanf("%s",str+1);
  len=strlen(str+1);
  for(int i=1;i<=len;i++)
  {
    if(str[i]=='/')
    {
    lc=1; num=0;
    for(int j=i-1;j>=i-sum;j--)
    {
    num+=(str[j]-'0')*lc;
    lc*=10;
    }
    a[++t]=num; sum=0;
    }
   else
   sum++;
 }
 lc2=len; cl=1; num=0;
while(str[lc2]!='/')
{
   num+=cl*(str[lc2]-'0');
   cl*=10;
   lc2--;
}
a[++t]=num;q=a[2];
 for(int i=1;i<=t;i++)
 {
    if(i==2) continue;
    q=q/gcd(a[i],q);
    if(q==1) 
    { cout<<"YES";return 0;}
 }
   cout<<"NO";
    return 0;
} 

————————————————
OclcK!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值