Divisor and Gcd 1、算术基本定理:n的质因数分解唯一 一些常见结论: 1.素数无限 2. (Π(n)表示<=n素数的个数) ————即n以下素数个数大约是 级别的 3. 级别的 (Pn表示素数) 4. 5.
2.整除的常见性质: a|b :b能被a整除 1.若, , 则 。 证明: $b = q1a,c = q2 a b±c = q1a±q2 a = (q1±q2)*a; ∴a|(b±c) a|c,b|c,(a,b) = 1(互质) ==> ab|c a|bc,(a,b) = 1 ==> a|c p|ab ==> p|a或p|b$
3.公约数和公倍数
竞赛中遇到能被xx整除的数的特征:
能被2 整除的数:个位上为2的倍数
能被4 整除的数:个位和十位所组成的两位数能被4整除
能被8 整除的数:百位、个位、十位所组成的三位数能被8整除(注意顺序)
能被5 整除的数:个位上为5的倍数
能被25 整除的数:十位和个位所组成的两位数能被25整除
能被125 整除的数:百位、十位、个位所组成的数能被125整除
能被3 整除的数:各个数位上的数字和能被3整除
能被9 整除的数:各个数位上的数字和能被9整除
能被11 整除的数:奇数位(从左往右数)上的数字和与偶数位上的数字和的差的绝对值能被11整除
能被7 整除的数:把个位数字截去,从余下的数中,减去个位数的2倍,如果差是7的倍数,则原数能被7整除,如果不好判断就递归处理
能被13 整除的数:把个位数字截去,从余下的数中,加上个位数的4倍,如果和是13的倍数,则原数能被13整除
能被17 整除的数:把个位数字截去,从余下的数中,加上个位数的5倍,如果和是17的倍数,则原数能被17整除,或把后三位截去,剩下的数与3倍后三位差的绝对值如果能被17整除,则原数能被17整除
能被19 整除的数:把个位数字截去,从余下的数中,加上个位数的2倍,如果和是19的倍数,则原数能被19整除,或把后三位截去,剩下的数与7倍后三位的差的绝对值如果能被19整除,则原数能被19整除
4.求公约数 1.欧几里得算法 d = a[1]; for(i = 2;i<=n;i++) d = gcd(d,a[i]); 时间复杂度O(n+log(max ai))
2.另一种公约数的算法 ·如果a,b都是奇数,那么 ·如果a是偶数,b是奇数,那么 ·如果a,b都是偶数,那么
5.有关公约数和公倍数的题目 题意:给你两个正整数 和 ,你可以说出有多少组解满足 并且
注意 和 这样是两个不同的解。
思路:从 的性质考虑:
若 ,则
显然,若 是无解的,那下面我们来看有解的情况:
转化为
转化为
那么现在问题转化为:满足 互质的,且他们的
因为要满足 互质的的条件,那么以{ }为例,至少有一个是 。
合法的情况是:
1){ } 排列方式3种
2){ } 排列方式3种
3){~ } 排列方式 种
综上,对于每一位有$3+3+(e_1-1)6 = 6 e_1$
那么接下来问题转化为对 进行质因数分解,再求种类数即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <bits/stdc++.h> using namespace std;typedef long long ll;int main () { int t; cin>>t; while (t--) { ll G,L; cin>>G>>L; if (L%G) { cout<<0 <<endl; continue ; } ll n = L/G; ll ans = 1 ; for (int i = 2 ;i<=n/i;i++) { if (n%i==0 ) { ll cnt = 0 ; while (n%i==0 ) n/=i,cnt++; ans*= 6ll *cnt; } } if (n>1 ) ans*=6ll ; cout<<ans<<endl; } return 0 ; }
题意:如果给你一个数 ,我们把 分成一些数字,问我们这些数字组最大的 是多少,对结果取模?
思路:首先可以明确,分成的这几个数一定是互质的。为什么呢?假设有两个数不互质,那么他们的 里面势必会少乘一个他们俩的 ,这样肯定不如都是互质的优。那么接下来,因为都是素数,那么我们可以先把素数预处理出来,然后用这些数填满 ,求填满 时最大的 。
很神奇的事情发生了,我们发现,是不是像我们有一个容量为 的背包,有 个物品,每个物品的体积是 ,可以取无限次。
对滴,是完全背包,那么接下来就可以开始写啦。
但是!这个时候我们又遇到一个问题,结果是要取模的,但是对于取模后的数我们是没有办法比大小的,中间步骤不取模又会炸,怎么办嘞?我们考虑用 来帮忙。
若$ab<c d则 有 log^a+log^b < log^c+log^d$
因为 在库函数里面是默认以 为底的,单调递增,那么我们的相对顺序没有变,而缩小了数字本身的大小,达到不会炸又可以比较大小的效果。
那么通过以上,问题解决。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <iostream> #include <algorithm> #include <string.h> using namespace std;typedef long long ll;const int N =2e4 +10 ;bool is_pri[N];int pri[N];int cnt;void init (int n) { memset (is_pri, true , sizeof (is_pri)); is_pri[1 ] = false ; cnt = 0 ; for (int i = 2 ; i <= n-1 ; i++) { if (is_pri[i]) pri[++cnt] = i; for (int j = 1 ; j <= cnt && i * pri[j] <= n-1 ; j++) { is_pri[i * pri[j]] = false ; if (i % pri[j] == 0 )break ; } } } ll n,mod; double dp[N];ll ans[N]; int main () { init (N); while (cin>>n>>mod) { for (int i = 0 ;i<=n;i++) dp[i] = 0 ,ans[i] = 1 ; for (ll i = 1 ;i<=cnt&&pri[i]<=n;i++) { for (ll j = n;j>=pri[i];j--) { for (ll k = 1 ,now = pri[i];now<=j;now*=pri[i],k++) { if (now<=j&&dp[j-now]+log (now*1.0 )>dp[j]) { dp[j] = dp[j-now]+log (now*1.0 ); ans[j] = ans[j-now]*now%mod; } } } } cout<<ans[n]%mod<<endl; } return 0 ; }
6. 裴蜀定理(Bézout’s lemma) 定理内容:
是一个关于最大公约数的定理 其内容是:设 是不全为零的整数,则存在整数 , 使得 存在整数解。
推论:整数 互素当且仅当存在 与 使得
证明:对任意 , , 一定是 的整数倍。最小的 是
思路:首先看两对数的情况 ,改写成裴蜀定理写法就是 。根据定理知 的最小非负值就是 ,这样对于 就合并成一个数 ,然后继续合并后面的。
由于 会返回负数,那只需要最后一步加个绝对值就ok啦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <bits/stdc++.h> using namespace std;int main () { int n; cin>>n; int x; cin>>x; for (int i = 2 ;i<=n;i++) { int y; cin>>y; x = __gcd(x,y); } cout<<abs (x)<<endl; return 0 ; }
思路:我们如果能得知最后能修的塔的数量,如果是奇数就先手赢,反之后手。
我们能修的塔: 即 ,根据裴蜀定理知 是 的整数倍。
那么数量就是
7.线性丢番图方程 方程 称为二元线性丢番图方程,其中 是已知整数, 是变量。
其实就是二维平面的一条直线,如果这条直线上有整数点那就有整数解,否则无。
如果存在一个解,那就有无数个解。
1.定理 因为 ,设 是整数,且 ,如果 不能被 整除,那么方程无解,否则有无数解。
如果其中一个特解为 ,那么通解为: ,其中 为任意整数。
eg1.线段上格点数 题意:二维平面上,给定两个格点 ,问线段 上除了 外还有几个格点?设
题解:
线段
对照 ,那么
令特解为 (这里用 也一样),代入限制条件
那么:
当 满足条件,那么有 个格点。
题意:
设青蛙 A 的出发点坐标是 ,青蛙 的出发点坐标是 。青蛙 一次能跳 米,青蛙 一次能跳 米,两只青蛙跳一次所花费的时间相同。纬度线总长 米。现在要你求出它们跳了几次以后才会碰面。
题解:
思路一:青蛙相遇时,初始位置的坐标差是 与跳的距离 的关系为
设
那么转化为我们常见的形式: ,其中 是我们要求的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #incldue<bits/stdc++.h> using namespace std;int main () { ll n,m,x,y,L; cin>>n>>m>>x>>y>>L; ll a = n-m,b = L,c = x-y; if (a<0 )a = -a,c = -c; ll d = exgcd (a,b,x,y); if (c%d != 0 )cout<<"impossible\n" ; else cout<<(x*(c/d)%(L/d)+(L/d))%(L%d)<<endl; return 0 ; }
思路二:同余
设
则有 注意这里a可能为负数, 只对非负整数有意义,所以处理一下:若
那么 ,接下来我们求
由 可解出 就是
设 ,那么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <bits/stdc++.h> using namespace std;typedef long long ll;ll p1,p2,m,n,l,a,b,x,y; ll exgcd (ll a,ll b,ll &x,ll &y) { if (b==0 ) { x = 1 ,y = 0 ; return a; } ll d = exgcd (b,a%b,y,x); y -= (a/b)*x; return d; } int main () { cin>>p1>>p2>>m>>n>>l; ll a = n-m,b = l,c = p1-p2; if (a<0 )a = -a,c = -c; ll d = exgcd (a,b,x,y); if (c%d)cout<<"Impossible\n" ; else { cout<<(c/d*x%(b/d)+(b/d))%(b/d)<<endl; } return 0 ; }
2.关于线性丢番图方程 ax+by=n 的解的个数 令 是互素的正整数, 是正整数。当 和 均非负时,线性丢番图方程 的解 是非负 的。
结论1: 时, 存在非负解。
证明:若 是方程的一对特解(不一定为非负解),则 可以取到方程的所以解(其中 为整数)
对于 ,存在解 ,此时有:
所以 ,所以此时 存在非负解。
结论2:如果 那么 没有非负解。
证明:
若没有非负解,即
即 ,又因为 互素
所以
令 其中
把, 代入
得 ,矛盾
所以此时 没有非负解。
反过来:
不妨假设
设结果为 ,则
可得
当然 时, 显然可以用 表示出来,不符合题意。
当 时,满足条件的 有最大值 ,显然 时候,有 的最大值
一种感性的解法:
引用自:(https://blog.csdn.net/dglyr/article/details/108135366 )

结论3:恰好有 个非负整数 使得方程 有非负解。
8. 扩展欧几里得(exgcd) 扩展欧几里得算法实际上就是对于 ,一定有一组整数解x,y使其成立。
即扩展欧几里得是求 的一组特解的方法。
如果要求 的解,那么可以先利用 求 的一组特解,然后再两边同乘 ,
那么得到 的一组解 ,其中
通解为:
具体做法:
由归纳假设存在 使得 即 于是就得到了 的解
商 余数
系数由
① ②
③ ④ ⑤ 设 可以找到一组解 那 ——————————————————再返回去找解
知道了特解之后,我们可以通过他求出方程的所有解
exgcd代码演示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <bits/stdc++.h> using namespace std;int exgcd (int a,int b,int &x,int &y) { if (b==0 ) { x = 1 ; y = 0 ; return a; } int d = exgcd (b,a%b,y,x); y -= (a/b)*x; return d; } int main () { int t; cin>>t; while (t--) { int a,b,x,y; cin>>a>>b; int d = exgcd (a,b,x,y); y = -y; while (x<0 ||y<0 )x+=b/d,y+=a/d; while (x>=b/d&&y>=a/d)x-=b/d,y-=a/d; cout<<x<<" " <<y<<endl; } return 0 ; }
最小非负整数解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <bits/stdc++.h> using namespace std;typedef long long ll;int exgcd (int a,int b,int &x,int &y) { if (b==0 ) { x = 1 ,y = 0 ; return a; } int d = exgcd (b,a%b,y,x); y -= (a/b)*x; return d; } int main () { int t; cin>>t; while (t--) { int a,b,x,y; ll m; cin>>a>>b>>m; int d = exgcd (a,b,x,y); if (m%d!=0 ) { cout<<-1 <<endl; continue ; } a/=d; b/=d; m/=d; __int128 xx = (__int128)x*m; xx%=b; if (xx<0 )xx+=b; __int128 yy = (m-a*xx)/b; if (yy<0 ) cout<<-1 <<endl; else cout<<(ll)xx<<" " <<(ll)yy<<endl; } return 0 ; }