• 一、数论算法


    (一)求最大公约数

    思路:辗转相除法(欧几里德算法)

     1 int Gcd(int a,int b)
     2 {
     3     if(a<b)
     4     {
     5         int tmp=a;
     6         a=b;
     7         b=tmp;
     8 }
     9     while(a%b)
    10     {
    11         int tmp=a%b;
    12         a=b;
    13         b=tmp;
    14 }
    15     return b;
    16 }
    gcd(以int为例)

    (二)求最小公倍数

    思路:对于整数a,b,lcm(a,b)=a*b/gcd(a,b)

    1 int Lcm(int a,int b)
    2 {
    3     int gcdnum=Gcd(a,b);
    4     return a*b/gcdnum;
    5 }
    lcm

     (三)求能整除n!的m的最大次幂

    思路:

    先将M质数分解,然后对M的每个素数因子求N!的最高次幂。

    例如M = 45 N = 67,其中45 = 3 ^ 2 * 5 ^ 1,即45的素数因子为3 567!中3的最高次幂为315的最高次幂为15.这样就可以确定67!中45的最高幂为15,因为67!中每2315就包含                 一个45,换句话说也就是求67!中包含了多少(3^2*5^1)这样的组合,也就是求min 31 / 2 15 / 1 )。

     1 #include <iostream>
     2 #include <cstring> 
     3 using namespace std;
     4 int getsum(int n,int x)
     5 {//计算1~n之间包含一个因子x的个数
     6     int ans=0;
     7     while(n)
     8     {
     9         ans+=n/x; n/=x;
    10     }
    11     return ans;
    12 }
    13 int main(int argc, char *argv[])
    14 {
    15     int n,m,i,j,t,c=1,temp,ans,a;
    16     cin>>t;
    17     while(t--)
    18     {
    19         cin>>m>>n;
    20         i=2; ans=1000000;
    21         while(m>1)
    22         {    
    23 a=0;
    24             while(m%i==0)
    25             {
    26                 a++; m/=i;
    27             }
    28             if(a)
    29             {
    30                 temp=getsum(n,i)/a;
    31                 if(ans>temp) ans=temp;
    32             }
    33             i++;
    34         }
    35         cout<<"Case "<<c++<<":"<<endl; 
    36         if(ans) cout<<ans<<endl;
    37         else cout<<"Impossible to divide"<<endl; 
    38     } 
    39     return 0;
    40 }
    View Code

    (四)全排列

    1、递归实现全排列(所有元素视为不同元素)

     1 template<class T>
     2 void Swap(T & a, T & b)
     3 {
     4     T temp = a;
     5     a = b;
     6     b = temp;
     7 }
     8 template<class T>
     9 void permutations(T list[], int k, int m)
    10 {
    11     if (k == m)
    12     {
    13         //copy(list,list+m+1,ostream_iterator<T>(cout,""));
    14         for (int i = 0; i <= m; i++)
    15             cout << list[i] << ' ';
    16         cout << endl;
    17     }
    18     else
    19     {
    20         for (int i = k; i <= m; i++)
    21         {
    22             Swap(list[k], list[i]);
    23             permutations(list, k + 1, m);
    24             Swap(list[k], list[i]);
    25         }
    26     }
    27 }
    View Code

    2、STL实现全排列(所有元素视为不同元素)

     1 void permutation(char* str, int length)
     2 {
     3     sort(str, str + length);
     4     do
     5     {
     6         for (int i = 0; i<length; i++)
     7             cout << str[i];
     8         cout << endl;
     9     } while (next_permutation(str, str + length));
    10 }
    View Code

    3、递归实现全排列(重复元素视为相同元素)

     1 template<class T>
     2 void permutation(T a[], int t, int n)
     3 {
     4     if (t == n)
     5     {
     6         for (int i = 0; i<n; i++)
     7         {
     8             cout << a[i] << " ";
     9         }
    10         cout << endl;
    11         return;
    12     }
    13     for (int j = t; j<n; j++)
    14     {
    15         int flag = 1;
    16         for (int r = t; r<j; r++)
    17         {
    18             if (a[r] == a[j])
    19             {
    20                 flag = 0;
    21                 break;
    22             }
    23         }
    24         if (flag == 0)
    25         {  //不符合条件跳入下一循环
    26             continue;
    27         }
    28         swap(a[j], a[t]);
    29         permutation(a, t + 1, n);
    30         swap(a[j], a[t]);
    31     }
    32 }
    View Code

    (五)组合

    1、对无重复的n个元素,求取m个元素的组合,并输出这些组合

     1 void dfs(int st, int cur)
     2 {//求n个不同的数中取m个元素的组合,调用:dfs(n-1,0);ininum为排好序的且无相同元素的数组,num为临时数组
     3     if (cur>=m)
     4         return;
     5     for (int i = st; i >= 0; --i)
     6     {
     7         int v = ininum[i];
     8         vis[v] = 1;
     9         num[cur] = v;
    10         if (cur == m - 1)
    11         {
    12             for (int j = 0; j < m; j++)
    13             {
    14                 cout << num[j] << ' ';
    15             }
    16             cout << endl;
    17         }
    18         dfs(i - 1, cur + 1);
    19     }
    20 }
    View Code

    2、对含有重复元素的n个元素(重复元素视为相同元素),求取m个不同元素的组合,并输出这些组合

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #define MAX_NUM 26
     4 int comb[MAX_NUM];
     5 int c1,c2;
     6 void combination(int m,int n) {
     7     int i,j;
     8 
     9     for (i=m;i>=n;i--) {
    10         comb[n]=i; /* 选择当前的“头”元素 */
    11         if (n>1) {
    12             combination(i-1,n-1); /* 进入下一次更小的组合问题 */
    13         } else { /* 满了需要的组合数,输出 */
    14             for (j=comb[0];j>0;j--) printf("%c",'A'+c1-comb[j]);
    15             printf("
    ");
    16         }
    17     }
    18     return;
    19 }
    20 int main(int argc,char **argv) {
    21     if (argc<3) {
    22         printf("%s 组合下标 组合上标
    ",argv[0]);
    23         return 1;
    24     }
    25     c1=atoi(argv[1]);
    26     if (c1<1 || MAX_NUM<c1) {
    27         printf("1<=组合下标<=%d
    ",MAX_NUM);
    28         return 2;
    29     }
    30     c2=atoi(argv[2]);
    31     if (c2<1 || c1<c2) {
    32         printf("1<=组合上标<=组合下标
    ");
    33         return 3;
    34     }
    35     comb[0]=c2;
    36     combination(c1,c2);
    37     return 0;
    38 }
    View Code

    (六)容斥原理

    原理:

    (1)|A∪B∪C|=|A|+|B|+|C|-|A∩B|-|A∩C|-|B∩C|+|A∩B∩C|

    (2)|A∪B∪C∪D|=|A|+|B|+|C|+|D|-|A∩B|-|A∩C|-|A∩D|-|B∩C|-|B∩D|-|C∩D|+|B∩C∩D|+|A∩C∩D|+|A∩B∩D|+|A∩B∩C|-|A∩B∩C∩D|

    (3)

    容斥原理可与二进制位运算枚举方案数相结合。

    (七)快速幂

    1、快速幂取模

    以下以求a的b次方来介绍

    把b转换成二进制数。

    该二进制数第i位的权为 2^(i-1)

    例如

    11的二进制是1011

    11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1

    因此,我们将a¹¹转化为算a^(2^0)*a^(2^1)*a^(2^3)

     1 long long  quickpow(long long   m , long long   n , long long   k){ 
     2     long long   ans = 1; 
     3     while(n){ 
     4         if(n&1) //取b二进制的最低位,判断和1是否相同,相同返回1,否则返回0,可用于判断奇偶 
     5             ans = (ans * m) % k; 
     6         n = n >> 1; //把b的二进制右移一位,即去掉其二进制位的最低位
     7         m = (m * m) % k; 
     8     } 
     9     return ans; 
    10 } 
    View Code

    2、矩阵快速幂

     1 //定义一个矩阵类,例如求(A^n)%mod 
     2 class Matrix { 
     3 public: 
     4      long long m[MAXN][MAXN]; //二维数组存放矩阵 
     5     Matrix(){} //对数组的初始化 
     6     void init(long long  num[MAXN][MAXN])//重载矩阵的乘法运算
     7     {
     8         for(int i = 0 ; i < MAXN ; i++)
     9         { 
    10             for(int j = 0 ; j < MAXN ; j++)
    11             { 
    12                 m[i][j] = num[i][j]; 
    13             } 
    14        } 
    15     } 
    16     friend Matrix operator*(Matrix &m1 ,Matrix &m2) //矩阵的快速幂
    17     { 
    18         int i, j, k; 
    19         Matrix temp; 
    20         for (i = 0; i < MAXN; i++) 
    21         { 
    22             for (j = 0; j < MAXN; j++) 
    23             { 
    24                 temp.m[i][j] = 0; 
    25                 for(k = 0 ; k < MAXN ; k++) //注意每一步都进行取模 
    26                    temp.m[i][j] += (m1.m[i][k] * m2.m[k][j])%mod 
    27                 temp.m[i][j] %= mod; 
    28            } 
    29         } 
    30         return temp; 
    31     } 
    32     friend Matrix quickpow(Matrix &M , long long n)//初始化为单位矩阵 
    33     { 
    34         Matrix tempans; 
    35         //初始化 
    36         for(int i = 0 ; i < MAXN ; i++)
    37         { 
    38             for(int j = 0 ; j < MAXN ; j++)
    39             { 
    40                 if(i == j) 
    41                     tempans.m[i][j] = 1; 
    42                 else 
    43                     tempans.m[i][j] = 0; 
    44             } 
    45         } 
    46         //快速幂(类似整数) 
    47         while(n)
    48         { 
    49             if(n & 1)    www.2cto.com
    50                 tempans = tempans * M; //已经重载了* 
    51             n = n >> 1; 
    52             M = M * M; 
    53         } 
    54        return tempans; 
    55     } 
    56 }; 
    57  
    58 int main() 
    59 { 
    60     Matrix A , ans; 
    61     long long T , n , k , sum; //数据类型为long long 
    62     long long num[MAXN][MAXN]; //输入的数据存入数组 
    63     scanf("%lld" , &T); 
    64     while(T--)
    65     { 
    66         scanf("%lld%lld
    ", &n , &k); 
    67         memset(num , 0 , sizeof(num)); 
    68         for(int i = 0 ; i < n ; i++)
    69         { 
    70             for(int j = 0 ; j < n ; j++) 
    71                 scanf("%lld" , &num[i][j]); 
    72         } 
    73         A.init(num);//初始化A矩阵 
    74         ans = quickpow(A , k);//求出矩阵的快速幂 
    75     } 
    76 } 
    77                     
    View Code

     

    作者:萌萌的美男子
    出处:http://www.cnblogs.com/ivan-count/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    67. @Transactional的类注入失败【从零开始学Spring Boot】
    66. No EntityManager with actual transaction available for current thread【从零开始学】
    Android ShapeDrawable之OvalShape、RectShape、PaintDrawable、ArcShape
    Android渲染器Shader:环状放射渐变渲染器RadialGradient(三)
    Android渲染器Shader:梯度渐变扫描渲染器SweepGradient(二)
    Android弹幕编程设计实现的解决方案(一)
    65.什么是IOC?【从零开始学Spring Boot】
    64.JPA命名策略【从零开始学Spring Boot】
    事务、视图和索引
    存储过程
  • 原文地址:https://www.cnblogs.com/ivan-count/p/7067439.html
Copyright © 2020-2023  润新知