本周刚开始学习数论,直接被虐爆。。
下面是几道基础题目的题解。
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!