文章目录
ps:以算法进阶指南为学习资料,主要用于复习背
质数:
埃氏筛
代码
for (int i=2;i<=sqrt(n);i++)
if (!vis[i])
for (int j=2;j<=n/i;j++)
vis[i*j]=true;
线性筛
代码
for (int i=2;i<=n;i++)
{
if (!v[i]) {p[++k]=i;v[i]=i;}
for (int j=1;j<=k;j++)
{
if (p[j]>v[i]||p[j]>n/i) break;
v[i*p[j]]=p[j];
}
}
约数
唯一分解定理相关(含互质内容)
定理:对于大于1的正整数N可以分解为
N
=
p
1
c
1
p
2
c
2
.
.
.
p
n
c
n
(
p
i
为
质
数
)
N=p_1^{c_1}p_2^{c_2}...p_n^{c_n}(p_i为质数)
N=p1c1p2c2...pncn(pi为质数)
推论:
N的正约数个数为:
∏
i
=
1
n
c
i
+
1
\prod_{i=1}^nc_i+1
∏i=1nci+1
N的所有正约数之和为:
∏
i
=
1
m
(
∑
j
=
0
c
i
(
p
i
)
j
)
\prod_{i=1}^m(\sum_{j=0}^{c_i}(p_i)^j)
∏i=1m(∑j=0ci(pi)j)
欧拉函数:
与正整数N互质的数的个数成为欧拉函数,记为
φ
\varphi
φ(N)
φ
(
N
)
\varphi(N)
φ(N)=
N
∗
∏
质
数
p
∣
N
1
−
1
p
N\ast \prod_{质数p|N} 1-{1\over{p}}
N∗∏质数p∣N1−p1
线形求欧拉函数:
代码
for (int i=2;i<=n;i++)
{
if (!p[i]) f[i]=i-1;
else if (i%(p[i]*p[i])==0) f[i]=f[i/p[i]]*p[i];
else f[i]=f[i/p[i]]*(p[i]-1);
ans+=(f[i])*2;
}
公约数
欧几里得算法:
用于求最大公约数
定理:
gcd(a,b)=gcd(b,a mod b)
代码:
int gcd(int a,int b)
{
if (b==0) return a;
return gcd(b,a%b);
}
更相减损术略
同余
扩展欧几里得(exgcd)
用于求ax+by=c,线性同余方程
裴蜀定理:
对于任意整数a,b,存在一对整数 x,y,满足ax+by=gcd(a,b);
证明:
欧几里得算法的最后,会得到gcd(a,0),即最大公约数为a。 当x=1是等式显然成立(a1+0y=a);
假设对于a,b当a=b,b=a mod b时等式成立 有一组解x1,y1 即bx1+(a mod b)y1=gcd(b,a mod b)
因为 a mod b=a- ⌊ a / b ⌋ \lfloor a/b \rfloor ⌊a/b⌋b 所以bx1+(a mod b)y1=bx1+(a- ⌊ a / b ⌋ \lfloor a/b \rfloor ⌊a/b⌋b)y1 将等号后的式子展开得 bx1+(a-b ⌊ a / b ⌋ \lfloor a/b \rfloor ⌊a/b⌋)y1=bx1+ay1-b ⌊ a / b ⌋ \lfloor a/b \rfloor ⌊a/b⌋y1=ay1+b(x1- ⌊ a / b ⌋ \lfloor a/b \rfloor ⌊a/b⌋y1) 所以可以对于a,b可以得到一组解x=y1,y=x1- ⌊ a / b ⌋ \lfloor a/b \rfloor ⌊a/b⌋y1 a=b,b=a
mod b即为欧几里得算法的过程 有因为最后gcd(a,0)时有一组整数解,所以根据数学归纳法一定会有解。 据此就可以求出一组特解
对于更一般的方程ax+by=c有解仅当c是gcd(a,b)的约数时(我懒得写证明了) 设ax+by=gcd(a,b)的有解为x1,y1
则对于方程ax+by=c 有解x=x1/(gcd(a,b)/c),y=y1/(gcd(a,b)/c);
代码:
int exgcd(int a,int b,int &x,int &y)
{
if (b==0) {x=1;y=0;return a;}
int Q=exgcd(b,a%b,x,y);
int x1=x;
x=y;
y=x1-(a/b)*y;
return Q;
}
对于求x为最小正整数时的解(我不太会证)
int exgcd(int a,int b,int &x,int &y)
{
if (b==0) {x=1;y=0;return a;}
int Q=exgcd(b,a%b,x,y);
int x1=x;
x=y;y=x1-(a/b)*y;
return Q;
}
int main()
{
cin>>a>>b>>c;
int ans=exgcd(a,b,x,y);
if (c%ans!=0) return 0;
x=x*(c/ans);y=y*(c/ans);
int d=b/ans;
if (d<0) d=-d;
x=x%d;
if (x<0) x+=d;
cout<<x;
}
费马小定理:
若p是质数,对于任意整数a , a p ≡ a ( m o d   p ) a^p\equiv a(mod\,p) ap≡a(modp)
欧拉定理:
若正整数a,n互质 则 a φ ( n ) ≡ 1 ( m o d   n ) a^{\varphi(n)}\equiv 1(mod\,n) aφ(n)≡1(modn)
欧拉定理推论:
若正整数a,n互质,则对于任意正整数b,有 a b ≡ a b   m o d   φ ( n ) ( m o d   n ) a^b\equiv a^{b\,mod\,\varphi(n)}(mod\,n) ab≡abmodφ(n)(modn)
求解乘法逆元:
emm;
当你要求a/b%p的时候,
a/b%p貌似不等于a%p/b%p
所以你需要求得一个数x
使a/b
≡
\equiv
≡a*x(mod p)
当 p为质数时,
x
=
b
p
−
2
x=b^{p-2}
x=bp−2就可以啦
不然啊,解方程呗- -
中国剩余定理:
设
m
1
m_1
m1
m
2
m_2
m2…
m
n
m_n
mn是两两互质的整数,m=
∏
i
=
1
n
m
i
\prod_{i=1}^nm_i
∏i=1nmi,
M
i
M_i
Mi=m/
m
i
m_i
mi,
t
i
t_i
ti是线性同余方程
m
i
m_i
mi
t
i
t_i
ti
≡
\equiv
≡ 1(mod p)的一个解。对于任意的n个正整数
a
1
a_1
a1,
a
2
a_2
a2…
a
n
a_n
an,方程组
{
x
≡
a
1
(
m
o
d
m
1
)
x
≡
a
2
(
m
o
d
m
2
)
.
.
.
x
≡
a
n
(
m
o
d
m
n
)
\begin{cases} x\equiv a_1(mod m_1)\\ x\equiv a_2(mod m_2)\\ ...\\ x\equiv a_n(mod m_n)\\ \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡a1(modm1)x≡a2(modm2)...x≡an(modmn)
有整数解,解为
∑
i
=
0
n
a
i
m
i
t
i
\sum_{i=0}^na_im_it_i
∑i=0naimiti
求解高次同余方程(BSGS=北上广深=拔山盖世)
ps:不熟
求解
a
x
a^x
ax
≡
\equiv
≡b(mod p)
蒟蒻只会a,p互质的
代码
long long m=(long long)ceil(sqrt(p));
long long ss=1;
h.clear();
for (int i=0;i<m;i++,ss=ss*a%p)
h[b*ss%p]=i;
long long s=1;
for (int i=0;i<=m;i++)
{
if (h.find(s)!=h.end()&&i*m-h[s]>=0) {cout<<i*m-h[s]<<endl;break;}
s=s*ss%p;
}
矩阵乘法
这个看缘分了啦
#include <bits/stdc++.h>
using namespace std;
long long n,a[2][2],f[2],P=10000;
void aaa()
{
long long c[2][2];
memset(c,0,sizeof(c));
for (int i=0;i<2;i++)
for (int j=0;j<2;j++)
for (int k=0;k<2;k++)
c[i][j]=(c[i][j]+a[i][k]*a[k][j]%P)%P;
memcpy(a,c,sizeof(c));
}
void aaaa()
{
long long c[2];
memset(c,0,sizeof(c));
for (int j=0;j<2;j++)
for (int k=0;k<2;k++)
c[j]=(c[j]+f[k]*a[k][j]%P)%P;
memcpy(f,c,sizeof(c));
}
int main()
{
cin>>n;
for (;n!=-1;)
{
if (n==0) {cout<<0<<endl;cin>>n;continue;}
f[0]=1;f[1]=0; a[0][0]=1; a[0][1]=1;a[1][0]=1;a[1][1]=0;
n=n-1;
for (;n>0;n=n>>1)
{
if (n&1) aaaa();
aaa();
}
cout<<f[0]<<endl;
cin>>n;
}
return 0;
}
斐波那契以表敬意
高斯消元
球形空间产生器:https://www.acwing.com/problem/content/209/
正常消元
#include <bits/stdc++.h>
using namespace std;
int n;
double a[22][22],b[22],c[22][22];
int main()
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
cin>>n;
for (int i=1;i<=n+1;i++)
for (int j=1;j<=n;j++)
cin>>a[i][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) {
c[i][j]=2*(a[i][j]-a[i+1][j]);
b[i]+=a[i][j]*a[i][j]-a[i+1][j]*a[i+1][j];
}
for (int i=1;i<=n;i++)
for (int j=i;j<=n;j++) {
if (fabs(c[i][j])<1e-8) {
for (int k=1;k<=n;k++) swap(c[i][k],c[j][k]);
swap(b[i],b[j]);
break;
}
for (int j=1;j<=n;j++) {
if (j==i) continue;
double m=c[j][i]/c[i][i];
for (int k=i;k<=n;k++)
c[j][k]-=c[i][k]*m;
b[j]-=b[i]*m;
}
}
for (int i=1;i<=n;i++)
printf("%.3lf ",b[i]/c[i][i]);
return 0;
}
开关问题:https://www.acwing.com/problem/content/210/
xor只好感性理解
#include <bits/stdc++.h>
using namespace std;
int T,n,a[30];
int J,x,y;
int ans;
int main() {
freopen("switch.in","r",stdin);
freopen("switch.out","w",stdout);
scanf("%d",&T);
for (int i1=1;i1<=T;i1++)
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]|=1<<i;
for (int i=1;i<=n;i++)
scanf("%d",&J),a[i]^=J;
for (;;) {
scanf("%d%d",&x,&y);
if (!x) break;
a[y]|=1<<x;
}
ans=1;
for (int i=1;i<=n;i++) {
for (int j=i+1;j<=n;j++)
if (a[j]>a[i]) swap(a[j],a[i]);
if (a[i]==0) {ans=1<<(n-i+1);break;}
if (a[i]==1) {ans=0;break;}
for (int k=n;k;k--)
if (a[i]>>k&1) {
for (int j=1;j<=n;j++)
if (i!=j&&(a[j]>>k&1)) a[j]^=a[i];
//a[j]^=a[i],a[i]的这一位和a[j]的这一位都为一,,需要将a[j]
//的这一位变为0,相同为0,异或运算,那取反可以吗?
//取反前面就变成1了,并且这个消元似乎和a[i]没有什么关系
//(总之不对吧),又或者整个题就是一个异或??
break;
}
}
if (ans==0) printf("Oh,it's impossible~!!\n");
else printf("%d\n",ans);
}
}
线性基:
我只能感性理解
装备购买:https://www.acwing.com/problem/content/211/
#include <bits/stdc++.h>
using namespace std;
int n,m,c[510],ans=0,ans_=0;
long double a[510][510];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%Lf",&a[i][j]);
for (int i=1;i<=n;i++)
scanf("%d",&c[i]);
for (int i=1;i<=m;i++)
{
int Min=1e9;
int r=0;
for (int j=i;j<=n;j++)
if (fabs(a[j][i])>1e-8&&c[j]<Min) Min=c[j],r=j;
if (r==0) continue;
swap(a[i],a[r]),swap(c[r],c[i]);
ans+=c[i];ans_++;
for (int j=1;j<=n;j++)
{
if (j==i) continue;
long double g=a[j][i]/a[i][i];
for (int k=i;k<=m;k++)
a[j][k]-=a[i][k]*g;
}
}
printf("%d %d",ans_,ans);
return 0;
}
xor的
XOR:https://www.acwing.com/problem/content/212/
#include <bits/stdc++.h>
using namespace std;
int T;
unsigned long a[10010];
int main()
{
cin>>T;
for (int i1=1;i1<=T;i1++) {
int n,Q;
unsigned long t;
bool fla=false;
cin>>n;
t=n;
for (int i=1;i<=n;i++)
cin>>a[i];
for (int i=1;i<=n;i++) {
for (int j=i+1;j<=n;j++)
if (a[j]>a[i]) swap(a[j],a[i]);
if (a[i]==0) {fla=true;t=i-1;break;}
for (int k=63;k>=0;k--)
if (a[i]>>k&1) {
for (int j=1;j<=n;j++)
if (i!=j&&(a[j]>>k&1)) a[j]^=a[i];
break;
}
}
cin>>Q;
cout<<"Case #"<<i1<<':'<<endl;
for (int i=1;i<=Q;i++) {
unsigned long k;
unsigned long ans=0;
cin>>k;
if (fla) k--;//能得到0
if (k>=(1LL<<t)) {cout<<-1<<endl;continue;}
for (int j=t-1;j>=0;j--)
if (k>>j&1) ans^=a[t-j];
cout<<ans<<endl;
}
}
return 0;
}
组合计数
多重集的排列数
n ! n 1 ! n 2 ! . . . n k ! n! \over n_1!n_2!...n_k! n1!n2!...nk!n!
多重集的组合数
k种数,选r个(r<=
n
i
n_i
ni)
n
i
n_i
ni表示第i种数的个数
(
k
−
1
k
+
r
−
1
)
{k-1}\choose{k+r-1}
(k+r−1k−1)
Lucas定理
若p是质数,则对于任意整数1
≤
\leq
≤m
≤
\leq
≤n
(
m
n
)
m \choose n
(nm)
≡
\equiv
≡
(
m
 
m
o
d
 
p
n
 
m
o
d
 
p
)
{m \, mod\, p} \choose {n \, mod \,p}
(nmodpmmodp)*
(
m
/
p
n
/
p
)
{m/p} \choose {n/p}
(n/pm/p) (mod p)
Catalan 数列
C a t n Cat_n Catn= ( n 2 n ) n + 1 {n \choose 2n}\over{n+1} n+1(2nn)
莫比乌斯反演
定义:
莫比乌斯函数:
μ
(
n
)
=
{
1
,
n
=
1
(
−
1
)
k
,
n
=
p
1
p
2
p
3
.
.
.
p
k
(
p
i
为
互
不
相
同
的
质
数
)
0
,
o
t
h
e
r
v
a
l
u
e
s
\mu(n)=\begin{cases} 1, & n=1\\ (-1)^k,&n=p_1p_2p_3...p_k(p_i为互不相同的质数)\\ 0, & other\ values \end{cases}
μ(n)=⎩⎪⎨⎪⎧1,(−1)k,0,n=1n=p1p2p3...pk(pi为互不相同的质数)other values
莫比乌斯反演定理:
形式1:
F ( n ) = ∑ d ∣ n f ( d ) ⇒ f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) F(n)=\sum_{d|n}f(d)\Rightarrow f(n)=\sum_{d|n}\mu(d)F({n\over d}) F(n)=d∣n∑f(d)⇒f(n)=d∣n∑μ(d)F(dn)
形式2:
F ( n ) = ∑ n ∣ d f ( d ) ⇒ f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) F(n)=\sum_{n|d}f(d)\Rightarrow f(n)=\sum_{n|d}\mu({d\over n})F(d) F(n)=n∣d∑f(d)⇒f(n)=n∣d∑μ(nd)F(d)
变形1:
f ( i ) = ∑ d = 1 ⌊ n i ⌋ g ( d ∗ i ) ⇒ g ( i ) = ∑ d = 1 ⌊ n i ⌋ μ ( d ) f ( d ∗ i ) f(i)=\sum_{d=1}^{\lfloor{n\over i}\rfloor}g(d*i)\Rightarrow g(i)=\sum_{d=1}^{\lfloor{n\over i}\rfloor}\mu(d)f(d*i) f(i)=d=1∑⌊in⌋g(d∗i)⇒g(i)=d=1∑⌊in⌋μ(d)f(d∗i)
变形2:
f ( i ) = ∑ i ∣ d , d ≤ n g ( d ) ⇒ g ( i ) = ∑ i ∣ d , d ≤ n μ ( d i ) f ( d ) f(i)=\sum_{i|d,d\leq n}g(d)\Rightarrow g(i)=\sum_{i|d,d\leq n}\mu({d\over i})f(d) f(i)=i∣d,d≤n∑g(d)⇒g(i)=i∣d,d≤n∑μ(id)f(d)
性质:
1.对于任意正整数n有
∑
d
∣
n
μ
(
d
)
=
{
1
,
n
=
1
0
,
n
>
1
\sum_{d|n}\mu(d)=\begin{cases} 1, & n=1\\ 0,&n>1\\ \end{cases}
d∣n∑μ(d)={1,0,n=1n>1
2.对于任意正整数n有
∑
d
∣
n
μ
(
d
)
d
=
φ
(
n
)
n
\sum_{d|n}{{\mu(d)}\over d}={\varphi(n)\over n}
d∣n∑dμ(d)=nφ(n)
概率和期望
这个东西似乎总是和DP搞一起,