专题:简单数论
我今天一定是学数学来的。学完我觉得我都可以参加数学竞赛了。晕头转向,哪哪都没学过。
Question_A
考察欧拉函数,打表打表!!!
普通打表太慢了,要用什么筛法,我学了学百度百科的打表方法,感觉好神奇哦,直接使用了三个性质没有套用求解公式,那样循环居然每个数都能走一遍(而且那个素数判断也镶嵌在其中太神奇了吧),但感觉有的会重复计算;然后还看了看其他人的打表方法大部分都用了那个公式,也是筛法;迷……
欧拉函数是指:对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) 。
通式:φ(x)=x*(1-1/p1)*(1-1/p2)*(1-1/p3)*(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1 (唯 一和1互质的数就是1本身)。
对于质数p,φ(p) = p - 1。注意φ(1)=1.
欧拉定理:对于互质的正整数a和n,有aφ(n) ≡ 1 mod n。
欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。
若n是质数p的k次幂,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质。
特殊性质:当n为奇数时,φ(2n)=φ(n)
欧拉函数还有这样的性质:
设a为N的质因数,若(N % a == 0 && (N / a) % a == 0) 则有E(N)=E(N / a) * a;若(N % a == 0 && (N / a) % a != 0) 则有:E (N) = E(N / a) * (a - 1)。
参考链接:www.cnblogs.com/soTired/p/4764321.html
附:百度百科上的打表模板:
/*
特性 :
1.若a为质数,phi[a]=a-1;
2.若a为质数,b mod a=0,phi[a*b]=phi[b]*a
3.若a,b互质,phi[a*b]=phi[a]*phi[b](当a为质数时,if b mod a!=0 ,phi[a*b]=phi[a]*phi[b])
*/
int m[n],phi[n],p[n],nump;
//m[i]标记i是否为素数,0为素数,1不为素数;p是存放素数的数组;nump是当前素数个数;phi[i]为欧拉函数
int make()
{
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!m[i])//i为素数
{
p[++nump]=i;//将i加入素数数组p中
phi[i]=i-1;//因为i是素数,由特性得知
}
for (int j=1;j<=nump&&p[j]*i<n;j++) //用当前已的到的素数数组p筛,筛去p[j]*i
{
m[p[j]*i]=1;//可以确定i*p[j]不是素数
if (i%p[j]==0) //看p[j]是否是i的约数,因为素数p[j],等于判断i和p[j]是否互质
{
phi[p[j]*i]=phi[i]*p[j]; //特性2
break;
}
else phi[p[j]*i]=phi[i]*(p[j]-1); //互质,特性3其,p[j]-1就是phi[p[j]]
}
}
}
Question_B
你敢相信么我题意看不懂,什么是约数、还是叫因数。。查了半天。 直接看定义比较明了;
1)一个正整数n按素因子分解:n=p1^a1*p2^a2*....*pk^ak,那么n的约数的个数为(a1+1)(a2+1)...(ak+1);
2)对于一个素数p,n!中按素因子分解,p的幂为 n/p+n/p^2+n/p^3...,其中/为整除
3)C(N,K)=N! / (K! (N-K)!) 整体约数个数:f(N!) - f(K!) - f((N-K)!).
还有就是,cout 输出时间和 printf 怎么差这么多,前者450ms,后者625ms。
本题上代码,因为太多知识点了
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int primes[341];
int numpr;
bool jupr(int n){
for(int i=2;i*i<=n;i++)
if(n%i==0)
return false;
return true;
}
void prime(){
for(int i=2;i<=432;i++)
if(jupr(i))
primes[numpr++]=i;
}
int cal(int a,int b){
int sum=0;
int flag=b;
while(a>=b){
sum+=a/b;
b*=flag;
}
return sum;
}
int main(){
prime();
int n,k;
while(~scanf("%d%d",&n,&k)){
long long ans=1;
for(int i=0;i<numpr&&primes[i]<=max(n,k);i++){
int a = cal(n,primes[i]);
int b = cal(k,primes[i]);
int c = cal(n-k,primes[i]);
ans*=(a-b-c+1);
}
printf("%lld\n",ans);
}
}
Question_C
什么积性函数性质啊,不会,只学会了最弱鸡的方法,欧拉啊欧拉,wuwuwu。
欧拉函数 φ(x)φ(x) :1到x-1有几个和x互质的数。
gcd(i,n)必定是n的一个约数。
若p是n的约数,那么gcd(i,n)==p的有φ(n/p)φ(n/p)个数,因为要使gcd(i,n)==p,i/p和n/p必须是互质的。
那么就是求i/p和n/p互质的i在[1,n]里有几个,就等价于 1/p,2/p,...,n/p 里面有几个和n/p互质,即φ(n/p)。
求和的话,约数为p的有φ(n/p),所以就是p*φ(n/p),同时把约数为n/p的加上去,i*i==n特判一下。
参考链接:https://www.cnblogs.com/flipped/p/5690123.html
太难了吧这也.......
#include<cstdio>
#include<cmath>
long long eular(int x){
int rea=x;
for(int i=2;i<=sqrt(x);i++){
if(x%i==0){
rea=rea/i*(i-1);
while(x%i==0)
x=x/i;
}
}
if(x>1)
rea=rea/x*(x-1);
return rea;
}
int main(){
long long n;
while(~scanf("%lld",&n)){
long long ans=0;
long long i;
for( i=1;i<sqrt(n);i++){
if(n%i==0)
ans+=i*eular(n/i)+n/i * eular(i);
}
if(i*i==n)
ans+=i*eular(i);
printf("%lld\n",ans);
}
}
后来看了看积性性质大概就公式吧 ,没太懂:f(n)=n*∏(1+ai*(pi-1)/pi)
#include <iostream>
using namespace std;
typedef long long ll;
int main()
{
ll n;
while(scanf("%lld",&n)==1){
ll ans=n;
for(ll i=2;i*i<=n;++i){
if(n%i==0){
ll a=0,p=i;
while(n%p==0){
++a;
n/=p;
}
ans=ans+ans*a*(p-1)/p;
}
}
if(n!=1)
ans=ans+ans*(n-1)/n;
printf("%I64d\n",ans);
}
return 0;
}
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
Question_E
欧几里德算法又称辗转相除法,是指用于计算两个正整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式gcd(a,b) = gcd(b,a mod b)。
转化为gcd(b×t+a,b)=gcd(a,b)(t为任意整数)
刚开始一直 Runtime Error , (sum-1)的值没把握好。