ACM中数论基础知识的运用.docx

上传人:b****9 文档编号:25695625 上传时间:2023-06-11 格式:DOCX 页数:26 大小:27.14KB
下载 相关 举报
ACM中数论基础知识的运用.docx_第1页
第1页 / 共26页
ACM中数论基础知识的运用.docx_第2页
第2页 / 共26页
ACM中数论基础知识的运用.docx_第3页
第3页 / 共26页
ACM中数论基础知识的运用.docx_第4页
第4页 / 共26页
ACM中数论基础知识的运用.docx_第5页
第5页 / 共26页
点击查看更多>>
下载资源
资源描述

ACM中数论基础知识的运用.docx

《ACM中数论基础知识的运用.docx》由会员分享,可在线阅读,更多相关《ACM中数论基础知识的运用.docx(26页珍藏版)》请在冰豆网上搜索。

ACM中数论基础知识的运用.docx

ACM中数论基础知识的运用

数论初步:

一,整除与因式分解:

1,算术基本定理:

n=a1^r1*a2^r2*a3^r3……

2,求素数:

(试除法,筛选法):

素数测试

费马小定理:

若p为素数,则对于任意小于

p的正整数a,有a(p-1)≡1(modp)

证明:

用欧拉定理直接得出

二次探测定理:

若p为素数,a2≡1(modp)

小于p的正整数解只有1和p-1

满足费马小定理和二次探测定理的数可以确定是素数

Miller-Rabin算法

算法步骤:

判定n是否为素数

令n-1=m*2j,m为奇数

随机在2到(n-1)之间取一个整数b

令v=bm,之后每次对v平方,当v=1时,若上一次的v既

不是1也不是(n-1),由二次探测定理,n不是素数,退出;

不断循环直到计算出b(n-1)

v=1,满足费马小定理,通过测试;否则n一定不是素数

选取几个不同的b多次测试

Miller-Rabin只能算一种测试,因为通过

测试的数不一定是素数,非素数通过测试

的概率是1/4

虽然一次测试的结果不一定令人满意,但

五六次随机测试基本可以保证正确率超

过99.9%

For(inti=2;i

{

For(intj=2,flay=1;j

If(I%j==0)

{

Printf(“i不是素数”);

flay=0;

}

Printf(“I是素数”);

}

3,

intm=sqrt(n+0.5);

intc=0;

memset(vis,0,sizeof(vis));

for(inti=2;i<=m;i++)

if(!

vis[i])

{

prime[c++]=i;

for(intj=i*i;j<=n;j+=i)vis[j]=1;

}

4,

intisprime[N];

intcnt;

intisok(intx)

{

for(inti=0;i

if(x%isprime[i]==0)return0;

return1;

}

voidgetprime()

{

isprime[0]=2;

isprime[1]=3;

cnt=2;

for(inti=5;i

if(isok(i))

isprime[cnt++]=i;

}

5,因式分解:

intFactor(intnum)

{

intm=0;

for(inti=0;i

{

if(num%isprime[i]==0)

{

arr[++m]=isprime[i];

r[m]=0;

while(num%isprime[i]==0&&num)

{

r[m]++;

num/=isprime[i];

}

}

}

if(num>1)

{

arr[++m]=num;

r[m]=1;

}

returnm;

}

6,求约数:

voiddfs(intnow,intq,intm,inta,intb)

{

if(flay)return;

if(q>a)return;

if(now==m+1)

{

q就是约数…..

return;

}

for(inti=0,t=1;i<=r[now];i++,t*=arr[now])

{

dfs(now+1,q*t,m,a,b);

}

}

例题分析:

Fzu上的题:

()

求一个数的真因子个数(不包括本身)。

n=p1^a1*p2^a2...pn^an.

那么真因子的个数就为:

(a1+1)*(a2+1)...(an+1)-1;

求n的所有真因子的和。

由n=p1^a1*p2^a2...pr^ar.

再由生成函数得(1+p1+p1^2...+p1^a1)*(1+p2+p2^2...+p2^a2)...(1+pr+pr^2...pr^ar).

求最小公倍数为M的至少两个数的最小和。

m=p1^a1*p2^a2...pn^an.

当m=1时:

sum=2

当m为素数时或m=p^n时:

sum=m+1

当m=2147483647:

sum=m+1.

sum=(p1^a1)+p2^a2...+pn^an.

1,(四省赛)题意:

求x,y,满足x+y=a,lcm(x,y)=b,x,y.

思路:

因为,a<20000,b<=10^9.一开始想法是从1到a/2枚举x,然后再判断lcm是否为b.可是数据组数有10^5这样会TEL。

然后再想想发现,因为lcm(x,y)=b,所以x必定为b的因子,于由只要枚举b的因子就行了。

常识:

1到10^6内平均的约数个数仅为13.97个。

voiddfs(intnow,intq,intm,inta,intb)

{

if(flay)return;

if(q>a)return;

if(now==m+1)

{

intx=q;

inty=a-x;

if(lcm(x,y)==b)

{

flay=true;

if(x>y)swap(x,y);

printf("%d%d\n",x,y);

}

return;

}

for(inti=0,t=1;i<=r[now];i++,t*=arr[now])

{

dfs(now+1,q*t,m,a,b);

}

}

变形题1:

求x,y,满足x+y=a,gcd(x,y)=b,x,y;

这可以看出b为x,y,的因子,要构造x,y,只要枚举b*k(k在1...)。

变形题2:

已知最大公约数gcd(x,y)=a,lcm(x,y)=b,求有多少个满足条件的?

voiddfs(intnow,intq,intm)

{

if(now==m+1)

{

//if(q%x==0)/*注释的方法会超时*/

//arr[p++]=q;/*设p=a*x,q=b*x,则由gcd(p,q)=x,得gcd(a,b)=1

得y=a*b*x,x*y=a*b*x*x,dfs枚举到的一个q后,q定等于b*x,

于是将x*y/q之得到的p,判断gcd(p,q)?

=x*/

intt=x*y/q;//x=gcd(p,q),y=lcm(p,q);p*q=gcd(p,q)*lcm(p,q);p=x*y/q;

if(gcd(t,q)==x)

c++;

return;

}

for(inti=0,t=1;i<=r[now];i++,t*=a[now])

dfs(now+1,q*t,m);

}

2,求最大的i使得n!

%k^i==0;(想想:

N!

如何分解….)

LLgetsum(LLn,LLx)

{

LLret=0;

while(n)

{

ret+=n/x;

n/=x;

}

returnret;

}

LLsolve(LLn,LLk)

{

LLans=(LL)inf,tmp;

LLxsum;

for(inti=0;i

{

if(k%isprime[i]==0)

{

xsum=0;

while(k%isprime[i]==0)

{

k/=isprime[i];

xsum++;

}

tmp=getsum(n,isprime[i]);

tmp/=xsum;

ans=min(ans,tmp);

}

}

if(k>1)

{

tmp=getsum(n,k);

ans=min(ans,tmp);

}

returnans;

}

二,殴拉函数:

定义:

对于正数n,殴拉函数是小于等于n的数中与n互质的数的个数:

f(n);

如果n是素数:

f(n)=n–1;f(n^k)=n^k–n^k-1;

容易证明φ(n)=p^k-p^(k-1)  

证明:

已知少于小于p^k的正整数个数为p^k-1个,其中 

和p^k不互质的正整数有{p×1,p×2,...,p×(p^(k-1)-1)}共计p^(k-1)-1个 

所以φ(n)=p^k-1-(p^(k-1)-1)=p^k-p^(k-1)

如果:

gcd(n,m)==1那么:

f(n*m)=f(n)*f(m);

Euler定理若gcd(a,n)=1则aϕ(n)≡1(modn)

•意义:

当b很大时ab≡abmodϕ(n)(modn),让

指数一直比较小

所以当:

n=p1^a1*p2^a2….

F(n)=(p1^a1–p1^a1-1)*(p2^a2–p2^a2-1)…..=>(p1-1)*(p2-1)*…..(p1^(a1-1)*p2^(a2-1)….);

F(n)=n*(1-1/p1)*(1-1/p2)…..

intelua(intn)

{

intret=1;

for(inti=2;i*i<=n;i++)

{

if(n%i==0)

{

n/=i;

ret*=i-1;

while(n%i==0)

{

n/=i;

ret*=i;

}

}

}

if(n>1)ret*=n-1;

returnret;

}

例题分析

1:

pku2478,求出分数a/b,其中数1<=a

思路:

(就是求小于n的把有整数a,并且sum(gcd(a,n)=1(1<=a

2,hdu2588:

有多少个正整数X满足:

1<=X<=N,并且gcd(X,N)>=M.

算法:

由:

1<=x<=N且(x,N)>=M;得(N/M,x/M)>=1推出:

(N/q,x')==1当{1<=x'<=N/q且q>=M};所以推出结果就是统计:

sum(euler(N/q)){当q|N,且q>=M}所以:

只要对N进行因子分解,求出它的约数,再统计约数q大于M的euler(N/q);

3,hdu3501(2010HIT多校)求小于N的不与N互质的数的和

思路:

容斥原理,求反面。

设:

小于N与N互质的数为:

a[1],a[2]…..a[phi(N)];

对于1<=i<=phi(N),因为:

gcd(N,a[i])=1可得gcd(N,N-a[i])=1;

(反证法,设gcd(N,N-a[i])=k>1,=>k|N且k|(N-a[i]),=>k|a[i]k|gcd(N,a[i])这与gcd(N,a[i])=1矛盾),

所以得s=a[1]+a[2]…+a[phi(N)]

S=N-a[1]+N-a[2]….+N–a[phi(N)]=>s=N*phi(N)/2;

变形题:

求小于N的所有数与N的最大公约数之和。

思路:

设K=gcd(i,n)(1<=i<=n)那么最大公约数为K的个数是phi(n/K),和就是K*phi(n/K).

4,去年的大连赛区现场题:

zju3547..

#include

#include

#include

#include

#include

#defineLLlonglong

#definemod1000000007

#definemaxn10000

usingnamespacestd;

intpi[1000],m;

intisprime[1300],cnt;

intisok(intx)

{

for(inti=0;i

if(x%isprime[i]==0)return0;

return1;

}

voidgetprime()

{

cnt=2;

isprime[0]=2;

isprime[1]=3;

for(inti=5;i

if(isok(i))isprime[cnt++]=i;

}

LLMypro(LLa,LLb,LLc)

{

LLret=0;

while(b>0)

{

if(b&1)

if((ret+=a)>c)ret-=c;

if((a+=a)>c)a-=c;

b>>=1;

}

returnret;

}

LLMypow(LLa,intb,LLc)

{

LLret=1;

while(b>0)

{

if(b&1)

ret=Mypro(ret,a,c);

a=Mypro(a,a,c);

b>>=1;

}

returnret;

}

LLn_30;

LLsum(intn)

{

LLret;

ret=Mypow(n,5,mod)*6%mod;

ret=(ret+15*Mypow(n,4,mod)%mod)%mod;

ret=(ret+10*Mypow(n,3,mod)%mod)%mod;

ret=(ret-n)%mod;

ret=(ret+mod)%mod;

ret=Mypro(n_30,ret,mod);

returnret;

}

LLdfs(intx,intn)

{

LLret=0;

LLtemp;

for(inti=x;i

{

temp=pi[i];

ret=(ret+(sum(n/temp)*(temp*temp%mod*temp%mod*temp%mod))%mod)%mod;

ret=((ret-(dfs(i+1,n/temp)*(temp*temp%mod*temp%mod*temp%mod)%mod))%mod+mod)%mod;

}

returnret%mod;

}

intmain()

{

getprime();

intcs;

intn;

scanf("%d",&cs);

n_30=Mypow(30,mod-2,mod);

while(cs--)

{

scanf("%d",&n);

if(isok(n))

{

printf("%lld\n",sum(n-1));

continue;

}

LLN=n;

m=0;

for(inti=0;i

{

if(n%isprime[i]==0)

{

pi[m++]=isprime[i];

n/=isprime[i];

while(n%isprime[i]==0)

n/=isprime[i];

}

}

if(n>1)pi[m++]=n;

n=N;

printf("%lld\n",((sum(n)-dfs(0,n))%mod+mod)%mod);

}

return0;

}

for (int ind = 1; ind < (1 << cnt); ++ind) 

{

            int token = ind;  

            LL tmp = 1;  

            int t = 0;  

            for (int j = 0; j < cnt; ++j, token >>= 1)  

            {  

                if (token & 0x1)  

                {  

                    tmp *= vt[j];  

                    ++t;  

                }  

            }  

            if (t & 0x1)  

            {  

                res = ( res + ( MOD - ( pow_mod(tmp, 4) * fun(n / tmp) % MOD ) ) ) % MOD;  

            }  

            else  

            {  

                res = ( res + pow_mod(tmp, 4) * fun(n / tmp) ) % MOD;  

            }  

        }  

Euler定理若gcd(a,n)=1则a^ϕ(n)≡1(modn)

•意义:

当b很大时a^b≡a^bmodϕ(n)(modn),让

指数一直比较小

 

A^xmodc=(A^(xmodphi(c)+phi(c)))modc;

费马小定理:

设p是素数,a是任意整数且a!

=0(modp),则有:

a^p-1=1(modp).

三,线性方程扩展殴几里德。

整除的性质

性质1:

a|b,b|c=>a|c

性质2:

a|b=>a|bc

性质3:

a|b,a|c<=>a|xb±yc

性质4:

a|b,b|a<=>a=±b

性质5:

a=kb±c<=>a,b的公因数与b,c的

公因数完全相同(利用性质3)

证明:

性质1:

由a|b,b|c得:

b=a*q1,c=b*q1=>c=a*q1*q2,命题得证。

性质2:

由a|b得:

b=a*q,两边同乘以c,就得b*c=a*q*c,命题得证。

性质3:

必要性:

由a|b,a|c,得:

b=a*q1,c=a*q2,推出bx±cy=a(q1*x±q2*y).取x=1,y=0及x=0,y=1,就推出充分性了,命题得证。

性质4:

必要性:

由a|b,b|a得b=a*q1,a=b*q2,推出a=a*q1*q2,因为a≠0所以q1*q2=1,q1=±1,充分性显而易见,命题得证。

性质5:

由性质3可得:

a是b与c的公约数,同时,a又是b的约数,所以,a与b的公约数为a等于b与c的公约数

欧几里德算法(辗转相除法,短除法)

原理:

若a≡r(modb),则gcd(a,b)=gcd(b,r)(利

用性质5证明)

a=q1*b+r1

b=q2*r1+r2

r1=q3*r2+r3

….

rn-1=qn-1*rn-2+rn-1

rn-2=qn*rn-1+rn

rn-1=qn+1*rn+0;

 

二元一次不定方程形中:

a*x+b*y=c.

求a*x+b*y=gcd(x,y),的一组解:

(x0,y0);

voidex_gcd(LLa,LLb,LL&d,LL&x,LL&y)

{

if(b==0)

{

d=a;

x=1,y=0;

}

else

{

ex_gcd(b,a%b,d,y,x);

y=y-x*(a/b);

}

}

那如果要求:

a*x+b*y=c的一组解(x1,y1).

由整除的性3可知:

当c%gcd(a,b)==0时,方程才有解。

(x0*c/g,y0*c/g);g=gcd(a,b);通解:

(x1+k*b/g,y1-k*a/g);

X1*a+y1*b=c=x2*a+y2*b;=>(x1-x2)*a=(y2-y1)*b

(x1-x2)*a1=(y2-y1)*b1其中:

a1=a/g,b1=b/g;

可得gcd(a1,b1)=1,那么(x1-x2)=b1*k,(y2-y1)=a1*k;

例题分析:

Joj去年的省赛题:

求最少的步数操作:

使得给定的Y,变成0,Y有四种操作:

Y+a,Y-a,Y+b,Y-b….;

算法过程:

设进行了x次的a+操作,进行了y次的b+操作,那么就可以得到方程:

a*x+b*y=Y;这就转换成了用殴几里德来解这个方程。

得到了它的一个解(x0,y0)。

通解:

x=x0+k*b/g,y=y0–k*a/g;

POJ2142

题目大意:

现有质量为a和b的砝码,数量不限

要求在天平上称出质量为d的物品,天平左右均可放砝码求一种可行方案,要求:

放置砝码数量尽可能少;数量相同时,总质量尽可能少

算法思路:

问题转化:

求ax+by=d的一组整数解(x,y),要求

|x|+|y|尽可能小,若相等,则a|x|+b|y|尽可能小(x<0,表示砝码和物体放在同一侧)

先求出不定方程的一组特解(x0,y0),令

m=gcd(a,b),a'=a/m,b'=b/m,则通解为

x=x0+b't,y=y0-a't(a',b'>0,t为整数)

要求输出(|x|+|y|)值最小的一组。

即(|x|+|y|)=|x0+b/g*t|+|y0-a/g*t|=f(t),简单分析,可以知道,  |x0+b/g*t|永远递增且大于零。

f(t)只有在  |y0-a/g*t|==0的时候才能取得最小值。

又因为t是整数,所以t应该取(y0*g/a)左右的整数值。

有了

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 天文地理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1