gcd
- //欧几里得,又叫做最大公约数
- int gcd(int a,int b)
- {
- return b==0?a:gcd(b,a%b);
- }
- int gcd(int big, int small)
- {
- if (small > big) swap(big, small);
- int temp;
- while (small != 0){ // 辗转相除法
- if (small > big) swap(big, small);
- temp = big % small;
- big = small;
- small = temp;
- }
- return(big);
- }
逆元
- //逆元
- gcd(a,b)=a*x+b*y;
- gcd(b,a%b,)
- ll extgcd(ll a,ll b,ll &x,ll &y)
- {
- if(b==0){
- x=1,y=0;
- return a;
- }
- ll d=extgcd(b,a%b,x,y);
- ll t=x;
- x=y;
- y=t-a/b*y;
- return d;
- }
- ll inv(ll a,ll mod)
- {
- ll x,y;
- extgcd(a,mod,x,y);
- return (mod+x%mod)%mod;
- }
快速幂
- ll fast_pow(ll a,ll b,ll mod)
- {
- ll ans=1;
- while(b){
- if(b&1)ans=ans*a%mod;
- a=a*a%mod;
- b>>=1;
- }
- return ans;
- }
- //快速幂
卡塔兰数
- #define ll long long
- ll Catelan[N];
- //用逆元求解
- ll extgcd(ll a, ll b, ll& x, ll& y)
- {
- ll d = a;
- if(b != 0){
- d = extgcd(b, a % b, y, x);
- y -= (a / b) * x;
- }else {
- x = 1;
- y = 0;
- }
- return d;
- }
- void pre()
- {
- int i;
- ll x, y;
- Catelan[0] = 1, Catelan[1] = 1;
- for(i = 2; i < N-5; i++)
- {
- Catelan[i] = Catelan[i-1]*(4*i-2) % mod;
- extgcd(i+1, mod, x, y);
- Catelan[i] = (Catelan[i]*((x+mod)%mod)) % mod;
- }
- }
矩阵快速幂求逆元
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #define MAXN 100
- #define LL long long
- #define MOD 10000
- using namespace std;
- struct Matrix
- {
- LL a[MAXN][MAXN];
- int r, c;//行数 列数
- };
- Matrix ori, res;//初始矩阵 和 结果矩阵
- void init()//初始化矩阵
- {
- memset(res.a, 0, sizeof(res.a));
- res.r = 2; res.c = 2;
- for(int i = 1; i <= 2; i++)//构造单位矩阵
- res.a[i][i] = 1;
- ori.r = 2; ori.c = 2;
- ori.a[1][1] = ori.a[1][2] = ori.a[2][1] = 1;
- ori.a[2][2] = 0;
- }
- Matrix multi(Matrix x, Matrix y)
- {
- Matrix z;
- memset(z.a, 0, sizeof(z.a));
- z.r = x.r, z.c = y.c;//新矩阵行数等于x矩阵的行数 列数等于y矩阵的列数
- for(int i = 1; i <= x.r; i++)//x矩阵的行数
- {
- for(int k = 1; k <= x.c; k++)//矩阵x的列数等于矩阵y的行数 即x.c = y.r
- {
- if(x.a[i][k] == 0) continue;//优化
- for(int j = 1; j<= y.c; j++)//y矩阵的列数
- z.a[i][j] = (z.a[i][j] + (x.a[i][k] * y.a[k][j]) % MOD) % MOD;
- }
- }
- return z;
- }
- void Matrix_mod(int n)
- {
- while(n)//N次幂
- {
- if(n & 1)
- res = multi(ori, res);
- ori = multi(ori, ori);
- n >>= 1;
- }
- printf("%lld\n", res.a[1][2] % MOD);
- }
- int main()
- {
- int N;
- while(scanf("%d", &N), N!=-1)
- {
- init();//初始化单位矩阵
- Matrix_mod(N);//矩阵快速幂
- }
- return 0;
- }
斯特灵近似
- ll steling(ll n)
- {
- return ll(log10(sqrt(4*acos(0.0)*n))+n*log10(n/exp(1.0)))+1;
- }
原文:https://blog.csdn.net/jamence/article/details/81660163
判定质数
- for(int i = 2 ; i * i <= n ; ++i) {
- if( n % i == 0 )
- {
- flag = 1 ;
- breke;
- }
- }
欧拉筛法
求 n 以内的所有质数
- for(int i = 2 ; i <= n ; ++ i ) {
- if( ! vis[i] )
- {
- cnt ++ ;
- p[cnt] = i ;
- }
- for( int j = 1 ; j <= cnt && i * p[j] <= n ; ++ j )
- {
- vis[p[j] * i ] = 1 ;
- if( i % p[j] == 0 ) break;
- }
- }
欧拉函数
方法一
- scanf("%lld", &n );
- if( n == 0 )
- return 0;
- long long m = n ;
- for(int i = 2 ; i * i <= m ; ++ i )//分解为质数乘积
- {
- if( m % i == 0 )
- {
- cnt ++ ;
- p[cnt] = i ;
- while( m % i == 0 )
- {
- m = m / i ;
- w[cnt] ++ ;
- }
- }
- }
- if( m != 1 )
- {
- cnt ++ ;
- p[cnt] = m ;
- w[cnt] = 1 ;
- }
- long long ans = 1 ;
- for(int i = 1 ; i <= cnt ; ++ i )
- {
- ans = ans * (p[i] - 1 ) ;
- for(int j = 1 ; j < w[i] ; j ++ )
- {
- ans = ans *p[i] ;
- }
- }
方法二
- ph[1] = 1 ;//结合欧式筛法,可以求出 n 以内每一个数的欧拉函数值
- scanf("%d", &n );
- for(int i = 2 ; i <= n ; ++ i ) {
- if(!vis[i]) {
- cnt ++ ;
- pr[cnt] = i ;
- ph[i] = i - 1 ;
- }
- for(int j = 1 ; j <= cnt && i * pr[j] <= n ; ++ j ) {
- vis[ i * pr[j] ] = 1 ;
- if( i % pr[j] == 0 ) {
- ph[ pr[j] * i ] = ph[i] * pr[j] ;
- break;
- }
- else
- ph [ pr[j] * i] = ph[i] * (pr[j] - 1 );
- }
- }
原文:https://blog.csdn.net/qq_44013342/article/details/88023526
分解质因数
(任何一个大于1的自然数,都能分解为若干个质数的幂的乘积,即)
- void get(int n)
- {
- for(int i = 2;i * i <= n;i++)
- if (n % i == 0){
- p[++m] = i;
- while(n % i == 0){
- w[m]++;
- n /= i;
- }
- }
- if (n != 1){
- p[++m] = n;
- w[m] = 1;
- }
- }
欧拉函数
求n以内与n互质的自然数的个数。先求出如上所述的“p”与“w”,再用以下公式:
或者
求二元一次不定方程的整数解
二元一次不定方程形如:ax+by=c(a、b、c是已知参数),当c是gcd(a,b)的倍数时(gcd(a,b)表a和b的最大公因数),才有整数解。可以用某种算法(即扩展欧几里得算法)求出不定方程ax+by=gcd(a,b)的解(此处x、y不等于上述x、y,因为在算法中把c看作了gcd(a,b),所以解出来x、y缩小了c/gcd(a,b))。
最后求整数解的通解,用如下公式:
其中t为任意整数
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- using namespace std;
- int d,x,y;
- void Sgcd(int a,int b,int &d,int &x,int &y){ //d、x、y要放在全局
- if (b == 0){
- x = 1;
- y = 0;
- d = a;
- return;
- }
- else{
- Sgcd(b,a % b,d,y,x);
- y -= a / b * x;
- }
- }
- int main()
- {
- int a,b,c;
- scanf("%d%d%d",&a,&b,&c);
- Sgcd(a,b,d,x,y);
- int m = c / d;
- printf("%d %d\n",x * m,y * m);//特殊解
- printf("%d %d\n",x * m + b / d,y * m - a / d);//其中一个通解,t=1;
- return 0;
- }
排列组合
(特殊的,0!=1)(以下n>=m)
排列:
表示从n个数中取出m个数来排列的方案总数,忽略顺序。例如:m=2时,(1,2)是一种,(2,1)是另一种。
组合:
表示从n个数中取出m个数来组合的方案总数,限制顺序。可以理解为从n个数中取出m个数有多少种取法。例如:m=2时,(1,2)和(2,1)是同一种。m=3时,(1,2,3)和(1,3,2)以及(2,1,3)等是同一种。
1、将n个相同的球放进m个不同的盒子里。球要放完,盒子不能为空,问有多少种放法。
解:题目等价于有n个球,要在两个球之间插板子(两个球之间最多能插一个),将球分为m个部分。n个球,有n-1个空隙可以插;m个部分,只用m-1个板子。
所以又可以等价于有n-1个板子,只需要取m-1个板子,问有多少种取法。因为反正都是把球分为m个部分,所以不同的板子得到的效果是一样的,所以可以理解为是同一种取法。这就是组合。答案:
2、将n个相同的球放进m个不同的盒子里。球要放完,盒子可以为空,问有多少种放法。
解:假设盒子不可以为空,放在此题种就等价于你已经放了m个球,还有n个球。所以此题等价于有n+m个球,放在m个盒子里,球要放完,盒子不能为空,这就是第一题了。答案:
3.将n个不同的球放在m个相同的盒子里。要求每个盒子里球的数量一样,球要放完(数据保证m是n的因子),问有多少种方法。
解:设n/m=x,即每个盒子里要放x个球。放球时,第一步:在n个球中取出x个球放在一个空盒里,第二步又在剩下的n-x个球中取出x个球放在一个空盒里......直至放完。所以第一步的方法总数是:,到第二步的方法总数是:,一共m步,以此类推。但是有这种情况:已经以某一种方案按要求将所有球放进m个盒子里了,现在却只是将A盒里的球放进B盒里,将B盒里原来的球放进A盒里。因为盒子是一样的,所以这是同一种方法。但计算时却以为是另一种方法。而这个等价于:已经以某一种方案按要求将所有球放进m个盒子里了,现在却只是将盒子调换位置,却认为是不同的方法。调换位置的方法有个。所以最后还要减去。答案:
原文:https://blog.csdn.net/weixin_44025325/article/details/87289230