Instructions
数学问题纯粹靠感觉啊。。。感觉很多定理都随缘啊。。。。大概总结一下8。
质数
无穷理论的证明:
设质数有有限的n个,依次为p₁,p₂,p₃,…,pn,则令N=p₁p₂p₃…pn。
1.若N+1为质数,则N+1一定是一个新的质数
2.若N+1为合数,则N一定存在一个不等于p₁,p₂,p₃,…,pn的质数因子。
质数判定的方法:
1.枚举,范围[2,sqrt(n)]。
2.筛选法(打表预处理)
1)、Eratosthenes筛法:用质数i筛掉i的倍数。
:2i,3i,4i…都是合数,一般从ii开始筛,因为2i已经筛过了,3i被3筛过了。
①效率接近线性
②存在重复筛选的问题(eg:15被3、5都筛了一次)
2)、欧拉线性筛:每个合数只用被最小的质因子筛掉。
①num[i]记录i的最小质因子,如果num[i]==i,则i就是质数。
②接下来从小到大枚举已确定的质数primes[j],则iprimes[j]的最小质因子一定是primes[j],除非primes[j]>num[i]。
O(n)的时间复杂度。
欧拉筛模板:
inline void OULA(){
for(int i=2;i<=maxn;i++){
if(!num[i])primes[++cnt]=i;
for(int j=1;i*primes[j]<=maxn;j++){
num[i*primes[j]]=true;
if(i%primes[j]==0)break;
}
}
}
约数
N=p1^c1*p2^c2*…*pm^cm。
①N的正约数{p1^b1*p2^b2*…*pm^bm|0<=bi<=ci}。
②N的正约数个数为(c1+1)(c2+1)…(cm+1)=∏i=1~m(ci+1)。
③N的所有正约数和为(1+p1+p1²+…+p1^c1)*…*(1+pm+pm²+…+pm^cm)。
求N的正约数集合:
枚举,1-sqrt(n),完全平方数需要特判。(约数有对称性定理)
对于正整数N,约数上限为2sqrt(n)个。
求1-N中所有数字的正约数:枚举时间复杂度O(Nsqrt(N))。
可以像Eratosthenes筛质数一样,i一定是i的倍数的约数,时间复杂度近似O(nlogn)。
欧拉筛+欧拉函数phi模板:
inline void OULA(){
for(int i=2;i<=maxn;i++){
if(!num[i]){
primes[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;i*primes[j]<=maxn;j++){
num[i*primes[j]]=true;
phi[i*primes[j]]=phi[i]*(primes[j]-1);
if(i%primes[j]==0){
phi[i*primes[j]]=phi[i]*primes[j];
break;
}
}
}
}
直接求phi模板:
inline int phii(int x){
ans3=n;
for(int i=2;i<=sqrt(n+1);i++){
if(x%i==0){
ans3=ans3*(i-1)/i;
while(x%i==0){
x/=i;
}
}
}
if(x>1){
ans3=ans3*(x-1)/x;
}
}
试除法求约数模板:
inline void Factor(int x){
for(int i=1;i<=sqrt(x+1);i++){
if(x%i==0){
ans[++cntt]=i;
if(i!=x/i)ans[++cntt]=x/i;
}
}
sort(ans+1,ans+cntt+1);
for(int i=1;i<=cntt;i++){
printf(" %lld",ans[i]);
ans2+=ans[i];
}
printf("
");
}
整数唯一分解:
a=p1e1*p2e2p3e3*…*pnen(p1<p2<…<pn);
b=p1f1*p2f2p3f3*…*pnfn。
则gcd(a,b)=p1min(e1,f1)*p2min(e2,f2)…pn^min(en,fn);
lcm(a,b)=p1max(e1,f1)*p2max(e2,f2)…pn^max(en,fn)。
其因数个数为(e1+1)(e2+1)…(en+1)。
inline void workk(int x){
vector<int>a;
vector<int>b;
int k=0;
for(int i=2;i<=sqrt(x+1);i++){
if(x%i==0){
k=0;
a.push_back(i);
while(x%i==0){
x/=i;
k++;
}
b.push_back(k);
}
}
if(x>1){
a.push_back(x);
b.push_back(1);
}
printf("%d=",n);
for(int i=0;i<a.size();i++){
printf("%d^%d",a[i],b[i]);
if(i+1!=a.size())printf("*");
}
printf("
");
}
矩阵
矩阵快速幂模板:
inline void Mull(){
memset(ans,0,sizeof(ans));
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
long long val=0;
for(int q=1;q<=k;q++){
val+=(ret[i][q]%m*a[q][j]%m)%m;
}
ans[i][j]=val%m;
}
}
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
ret[i][j]=ans[i][j];
}
}
}
inline void Mull_Self(){
memset(ans,0,sizeof(ans));
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
long long val=0;
for(int q=1;q<=k;q++){
val+=(a[i][q]%m*a[q][j]%m)%m;
}
ans[i][j]=val%m;
}
}
for(int i=1;i<=k;i++){
for(int j=1;j<=k;j++){
a[i][j]=ans[i][j];
}
}
}
inline void Quick_Pow(long long x){
memset(ret,0,sizeof(ret));
for(int i=1;i<=k;i++){
ret[i][i]=1;
}
while(x){
if(x&1)Mull();
Mull_Self();
x>>=1;
}
}
快速幂优化递推例题链接:递推的矩阵优化
莫比乌斯反演
对于f(x),可以很方便得到∑d|nf(d),即:F(n)=∑d|nf(d)。
两个重要的反演公式:
1.F(n)=sigma n|k(f(k)) -->f(n)=sigma n|k(Mo[k/n]F(k))
2.F(n)=sigma k|n(f(k)) -->f(n)=sigma k|n(Mo[k]F(n/k))
莫比乌斯(Möbius)函数:
①μ(d)=1,d=1;
②μ(d)=(-1)ⁿ,d=p₁p₂p₃…pn;
③μ(d)=0,d=others。(存在pn²质因子)
莫比乌斯函数预处理模板:
inline void Mobius(){
Mo[1]=1;
for(int i=2;i<=maxn-1;i++){
if(!num[i]){
primes[++cnt]=i;
Mo[i]=-1;
}
for(int j=1;j<=cnt&&i*primes[j]<maxn;j++){
num[i*primes[j]]=true;
Mo[i*primes[j]]=Mo[i]*(-1);
if(i%primes[j]==0){
Mo[i*primes[j]]=0;
break;
}
}
}
}
例题:HAOI2011
卡特兰数
例题:NOIP普及组2003