ACM中数论基础知识的运用.docx
《ACM中数论基础知识的运用.docx》由会员分享,可在线阅读,更多相关《ACM中数论基础知识的运用.docx(26页珍藏版)》请在冰豆网上搜索。
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;jIf(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;iif(x%isprime[i]==0)return0;
return1;
}
voidgetprime()
{
isprime[0]=2;
isprime[1]=3;
cnt=2;
for(inti=5;iif(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;iif(x%isprime[i]==0)return0;
return1;
}
voidgetprime()
{
cnt=2;
isprime[0]=2;
isprime[1]=3;
for(inti=5;iif(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)左右的整数值。
有了