数论笔记


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}} NpN1p1

线形求欧拉函数:

代码

	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/bb 所以bx1+(a mod b)y1=bx1+(a- ⌊ a / b ⌋ \lfloor a/b \rfloor a/bb)y1 将等号后的式子展开得 bx1+(a-b ⌊ a / b ⌋ \lfloor a/b \rfloor a/b)y1=bx1+ay1-b ⌊ a / b ⌋ \lfloor a/b \rfloor a/by1=ay1+b(x1- ⌊ a / b ⌋ \lfloor a/b \rfloor a/by1) 所以可以对于a,b可以得到一组解x=y1,y=x1- ⌊ a / b ⌋ \lfloor a/b \rfloor a/by1 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 &ThinSpace; p ) a^p\equiv a(mod\,p) apa(modp)

欧拉定理:

若正整数a,n互质 则 a φ ( n ) ≡ 1 ( m o d &ThinSpace; n ) a^{\varphi(n)}\equiv 1(mod\,n) aφ(n)1(modn)

欧拉定理推论:

若正整数a,n互质,则对于任意正整数b,有 a b ≡ a b &ThinSpace; m o d &ThinSpace; φ ( n ) ( m o d &ThinSpace; n ) a^b\equiv a^{b\,mod\,\varphi(n)}(mod\,n) ababmodφ(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=bp2就可以啦
不然啊,解方程呗- -

中国剩余定理:

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} xa1(modm1)xa2(modm2)...xan(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+r1k1)

Lucas定理

若p是质数,则对于任意整数1 ≤ \leq m ≤ \leq n
( m n ) m \choose n (nm) ≡ \equiv ( m &ThinSpace; m o d &ThinSpace; p n &ThinSpace; m o d &ThinSpace; 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, &amp; n=1\\ (-1)^k,&amp;n=p_1p_2p_3...p_k(p_i为互不相同的质数)\\ 0, &amp; 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)=dnf(d)f(n)=dnμ(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)=ndf(d)f(n)=ndμ(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=1ing(di)g(i)=d=1inμ(d)f(di)

变形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)=id,dng(d)g(i)=id,dnμ(id)f(d)

性质:

1.对于任意正整数n有
∑ d ∣ n μ ( d ) = { 1 , n = 1 0 , n &gt; 1 \sum_{d|n}\mu(d)=\begin{cases} 1, &amp; n=1\\ 0,&amp;n&gt;1\\ \end{cases} dnμ(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} dndμ(d)=nφ(n)

概率和期望

这个东西似乎总是和DP搞一起,

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值