第一章:数论
知识点:
(就只整理了蒟蒻自己学的比较深刻的东西)
1.gcd
2.同余
3.最大公约数
1.辗转相除法(gcd板子)
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
2.二进制优化gcd(好像用的不是很多,还是写一下吧)
LL gcd(LL x,LL y)
{
int i,j;
if(!x) return y; if(!=y) return x;
for(i=0;0==(x&1);i++) x>>=1;//去掉所有的2
for(j=0;0==(y&1);i++) y>>=1;//去掉所有的2
if(j<i) i=j;
while(1)
{
if(x<y) x^=y, y^=x,x^=y;//若x<y交换x,y
if(0==(x-=y)) return y<<i;
//若x==y,gcd==x==y(就是在辗转减,while(1)控制)
while(0==(x&1)) x>>=1;//去掉所有的2
}
}
3.最小公倍数:
L
C
M
(
x
,
y
)
=
x
∗
y
÷
g
c
d
(
x
,
y
)
LCM(x,y) = x * y \div gcd(x,y)
LCM(x,y)=x∗y÷gcd(x,y)
4.扩展欧几里得算法(exgcd板子)
LL exgcd(LL a,LL b,LL &x,LL &y)
{
LL s,LL t;
if(!b){x=0,y=1;return a;}
s=exgcd(b,a%b,x,y);
t=y;x=y;y=t-a/b*y;
return s;
}
5.解线性同余方程
LL t=gcd(a,b);
if(c%t!=0) printf("NO solution\n");
a/=t; b/=t; c/=t;
exgcd(a,b,x,y);
x=((c*x)%b+b)%b;
printf("%lld\n",x);
4. 逆元
快速幂求逆元:
LL ksm(LL a,LL b,,LL key)
{
LL tmp=b;
for(;a;a>>=1,tmp=(tmp*tmp%key)) if(a&1) tmp=(tmp*b%ket);
return tmp;
}
exgcd求逆元:
LL a,b,x,y;
exgcd(LL a,LL b,LL x,LL y);
5.中国剩余定理(china板子)
#include<bits/stdc++.h>
#define ll long long
#define sea 1100000
using namespace std;
ll m[sea],aa[sea],ans,n;
template<typename T>inline void read(T &x)
{
x=0;T f=1,ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
x*=f;
}
ll hhhhhh(ll a,ll b,ll mod)
{
ll res=0;
while(b>0)
{
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0){x=1;y=0;return a;}
ll gcd=exgcd(b,a%b,x,y);
ll tp=x;
x=y; y=tp-a/b*y;
return gcd;
}
ll china()
{
ll x,y;
ll M=m[1],ans=aa[1];
for(ll i=2;i<=n;i++)
{
ll a=M,b=m[i],c=((aa[i]-ans)%b+b)%b;
ll gcd=exgcd(a,b,x,y),bg=b/gcd;
// if(c%gcd!=0) return -1;
x=hhhhhh(x,c/gcd,bg);
ans+=x*M;
M*=bg;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
int main()
{
read(n);
for(ll i=1;i<=n;i++)
read(m[i]),read(aa[i]);
printf("%lld",china());
return 0;
}
6.斐波那契数
由于好好的手推了一下通项公式,觉得比矩阵快速幂快多了,
F
(
n
)
=
5
5
[
(
1
+
5
2
)
n
−
(
1
−
5
2
)
n
]
F_{(n)}=\frac{\sqrt{5}}{5}[(\frac{1+\sqrt{5}}{2})^{n}-(\frac{1-\sqrt{5}}{2})^{n}]
F(n)=55[(21+5)n−(21−5)n]
代码中的通项:
x
=
k
⋅
(
−
1
)
i
f
(
i
−
1
)
x=k⋅(−1)^if(i-1)
x=k⋅(−1)if(i−1)
y
=
k
⋅
−
1
i
+
1
i
f
(
i
−
2
)
y=k⋅-1^i+1^if(i-2)
y=k⋅−1i+1if(i−2)
for(int p0=1, p1=1, x=0, y=1; p0+p1<=n; p1=p0+p1, p0=p1-p0, x=y-x, y=y-x)
{
tx=1ll*x*n, ty=1ll*y*n;
fx=tx%p1; if(fx<=0) fx+=p1; fy=ty-(fx-tx)/p1*p0;
sy=ty%p0; if(sy<=0) sy+=p0; sx=tx-(sy-ty)/p0*p1;
if(fy<=0||sx<=0) break;
ans=(ans+(sx-fx)/p1+1)%1000000007;
}
printf("%d",ans);
7.卡特兰数
公式:
1.递推公式 1:
f
(
n
)
=
∑
i
=
0
n
−
1
f
(
i
)
×
f
(
n
−
i
−
1
)
f(n)=\sum_{i=0}^{n-1} f(i)×f(n-i-1)
f(n)=i=0∑n−1f(i)×f(n−i−1)
2.递推公式 2:
f
(
n
)
=
f
(
n
−
1
)
×
(
4
n
−
2
)
n
+
1
f(n)=\frac{f(n-1)×(4n-2)}{n+1}
f(n)=n+1f(n−1)×(4n−2)
3.组合公式 1:
f
(
n
)
=
C
2
n
n
n
+
1
f(n)=\frac{C^n_{2n}}{n+1}
f(n)=n+1C2nn
4.组合公式 2:
f
(
n
)
=
C
2
n
n
−
C
2
n
n
−
1
f(n)=C^n_{2n}-C^{n-1}_{2n}
f(n)=C2nn−C2nn−1
int main()
{
scanf("%d",&n);
catlan[0]=catlan[1]=1;
for(int i=2;i<=n;i++)
for(int j=0;j<i;j++)
catlan[i]=((catlan[j]*catlan[i-j-1])%mod+catlan[i])%mod;
printf("%lld",catlan[n]);
return 0;
}
8.解高次同余方程(BSGS板子)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL A,B,C,ans,D,y,x,m,t;
class hash
{
public:
hash(){memset(a,0xff,sizeof(a));}
int locate(LL x)
{
LL l=x%MOD;
while(a[l]!=x&&a[l]!=-1) l=(l+1)%MOD;
return l;
}
void insert(LL x,LL va)
{
LL l=locate(x);
if(a[l]==-1) a[l]=x,v[l]=va;
}
LL get(LL x)
{
LL l=locate(x);
return a[l]==x?v[l]:-1;
}
void clear(){memset(a,0xff,sizeof(a));}
private:
static const LL MOD=100007;
LL a[MOD+100],v[MOD+100];
}H;
LL exgcd(LL a,LL b,LL &x ,LL &y)
{
LL t,s;
if(!b){x=1,y=0; return a;}
s=exgcd(b,a%b,x,y);
t=x,x=y,y=t-a/b*y;
return s;
}
int main()
{
while(scanf("%lld%lld%lld",&C,&A,&B)!=EOF)
{
H.clear();
m=ceil(sqrt(double(C))); t=1;
for(int i=0;i<m;i++) H.insert(t,i),t=t*A%C;
D=1; ans=-1;
for(int i=0;i<m;i++)
{
exgcd(D,C,x,y);//exgcd求逆元
x=((x*B)%C+C)%C;///B*x=B*D^(-i*m)
y=H.get(x);//匹配即可
if(y!=-1){ans=i*m+y; break;}
D=(D*t)%C;///D=t^i,(t=A^m)
}
if(ans==-1) printf("no solution\n");
else printf("%lld\n",ans);
}
return 0;
}
9.欧拉函数的线性筛
#include<stdio.h>
#define LL long long
using namespace std;
const int sea=1000001;
int a[sea],b[sea],f[sea],k,x;
LL s[sea];
void xxs()
{
int n=sea,i,j;
for(i=2;i<=n;i++) a[i]=0;
for(i=2;i<=n;i++)
{
if(a[i]==0) a[i]=i,b[++k]=i;
for(int j=1;j<=k&&i*b[j]<=n;j++)
{
a[i*b[j]]=b[j];
if(i%b[j]==0) break;
}
}
f[1]=1;
for(i=2;i<=n;i++)
if(a[i/a[i]]==a[i]) f[i]=f[i/a[i]]*a[i];
else f[i]=f[i/a[i]]*(a[i]-1);
for(i=2;i<=n;i++) s[i]=s[i-1]+f[i];
}
int main()
{
xxs();
while(scanf("%d",&x)!=EOF)
{
if(x==0) break;
printf("%lld\n",s[x]);
}
return 0;
}
大概就是这样吧,总的来说,这次跟着数学一本通对数论进行系统的学习,其实还是蛮好的,比较完整的学习了一些知识。
所以还是比较推荐学习这本书的。
下面打算接着往下学一章,没有按照顺序,就是想学什么就学什么,那下一章就矩阵吧。