zoukankan      html  css  js  c++  java
  • 程序中的数学

    一,大数

    下面为我的高精度整数模板

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    #define MAXN 500
    struct BigNum {
        int num[MAXN];
        int len;
    };
    //高精度比较 a > b return 1, a == b return 0; a < b return -1;
    int Comp(BigNum &a, BigNum &b) {
        int i;
        if (a.len != b.len)
            return (a.len > b.len) ? 1 : -1;
        for (i = a.len - 1; i >= 0; i--)
            if (a.num[i] != b.num[i])
                return (a.num[i] > b.num[i]) ? 1 : -1;
        return 0;
    }
    //高精度加法
    BigNum Add(BigNum &a, BigNum &b) {
        BigNum c;
        int i, len;
        len = (a.len > b.len) ? a.len : b.len;
        memset(c.num, 0, sizeof(c.num));
        for (i = 0; i < len; i++) {
            c.num[i] += (a.num[i] + b.num[i]);
            if (c.num[i] >= 10) {
                c.num[i + 1]++;
                c.num[i] -= 10;
            }
        }
        if (c.num[len])
            len++;
        c.len = len;
        return c;
    }
    //高精度减法,保证a >= b
    BigNum Sub(BigNum &a, BigNum &b) {
        BigNum c;
        int i, len;
        len = (a.len > b.len) ? a.len : b.len;
        memset(c.num, 0, sizeof(c.num));
        for (i = 0; i < len; i++) {
            c.num[i] += (a.num[i] - b.num[i]);
            if (c.num[i] < 0) {
                c.num[i] += 10;
                c.num[i + 1]--;
            }
        }
        while (c.num[len - 1] == 0 && len > 1)
            len--;
        c.len = len;
        return c;
    }
    BigNum Mul(BigNum &a, BigNum &b) {
        int i, j, len = 0;
        BigNum c;
        memset(c.num, 0, sizeof(c.num));
        for (i = 0; i < a.len; i++) {
            for (j = 0; j < b.len; j++) {
                c.num[i + j] += (a.num[i] * b.num[j]);
                if (c.num[i + j] >= 10) {
                    c.num[i + j + 1] += c.num[i + j] / 10;
                    c.num[i + j] %= 10;
                }
            }
        }
        len = a.len + b.len - 1;
        while (c.num[len - 1] == 0 && len > 1)
            len--;
        if (c.num[len])
            len++;
        c.len = len;
        return c;
    }
    BigNum Pow(BigNum &a, int n) {
        BigNum ans;
        ans.num[0] = 1, ans.len = 1;
        while (n) {
            if (n & 1)
                ans = Mul(ans, a);
            a = Mul(a, a);
            n >>= 1;
        }
        return ans;
    }
    //高精度除以低精度,除的结果为c, 余数为f
    void Div1(BigNum &a, int &b, BigNum &c, int &f) {
        int i, len = a.len;
        memset(c.num, 0, sizeof(c.num));
        f = 0;
        for (i = a.len - 1; i >= 0; i--) {
            f = f * 10 + a.num[i];
            c.num[i] = f / b;
            f %= b;
        }
        while (len > 1 && c.num[len - 1] == 0)
            len--;
        c.len = len;
    }
    //高精度*10
    void Mul10(BigNum &a) {
        int i, len = a.len;
        for (i = len; i >= 1; i--)
            a.num[i] = a.num[i - 1];
        a.num[i] = 0;
        len++;
        while (a.num[len - 1] == 0 && len > 1)
            len--;
        a.len = len;
    }
    
    //高精度除以高精度,除的结果为c,余数为f
    void Div2(BigNum &a, BigNum &b, BigNum &c, BigNum &f) {
        int i, len = a.len;
        memset(c.num, 0, sizeof(c.num));
        memset(f.num, 0, sizeof(f.num));
        f.len = 1;
        for (i = len - 1; i >= 0; i--) {
            Mul10(f);
            f.num[0] = a.num[i];
            while (Comp(f, b) >= 0) {
                f = Sub(f, b);
                c.num[i]++;
            }
        }
        while (len > 1 && c.num[len - 1] == 0)
            len--;
        c.len = len;
    }
    void print(BigNum &a) {  //输出大数
        int i;
        for (i = a.len - 1; i >= 0; i--)
            printf("%d", a.num[i]);
        puts("");
    }
    
    void Init(BigNum &a, char *s, int &tag) {  //字符串转化为大数
        memset(a.num, 0, sizeof(a.num));
        int i = 0, j = strlen(s);
        if (s[0] == '-') {
            j--;
            i++;
            tag *= -1;
        }
        a.len = j;
        for (; s[i] != ''; i++, j--)
            a.num[j - 1] = s[i] - '0';
    }
    
    int main() {
        freopen("data.txt", "r", stdin);
        BigNum a, b, c, f;
        char s1[100], s2[100];
        while (~scanf("%s%s", s1, s2)) {
            int tag = 1;
            Init(a, s1, tag);
            Init(b, s2, tag);
            Div2(a, b, c, f);
            if (tag < 0)
                putchar('-');
            print(c);
            print(f);
    //        c = Pow(a, 2);
    //        print(c);
        }
        return 0;
    }
    /*
    99999999999999999999999999999980000000000000000000000000000001 9999999999999999999999999999999
     */

    JAVA中BigInteger大整数类 和 BigDecimal大浮点数类

    基本函数:

     1.valueOf(parament); 将参数转换为制定的类型

      比如 int a=3;

           BigInteger b=BigInteger.valueOf(a);

           则b=3;

           String s=”12345”;

           BigInteger c=BigInteger.valueOf(s);

           则c=12345;

     2.add(); 大整数相加

     3.subtract(); 相减

     4.multiply(); 相乘

     5.divide();    相除取整

     6.remainder();取余

     7.pow();   a.pow(b)=a^b

     8.gcd();   最大公约数

     9.abs(); 绝对值

     10.negate();取反数

     11.mod(); a.mod(b)=a%b=a.remainder(b);

     12.max(); min();

     13.punlic int comareTo();

     14.boolean equals(); 是否相等

     15.BigInteger构造函数:BigInteger(String val);

    基本常量:BigInteger.ONE   BigInteger.TEN   BigInteger.ZERO

    读入:用Scanner类定义对象进行控制台读入,Scanner类在java.util.*包中

     Scanner cin=new Scanner(System.in);// 读入

     while(cin.hasNext()) {  //等同于!=EOF

       int n;

       BigInteger m;

       n=cin.nextInt(); //读入一个int;

       m=cin.BigInteger();//读入一个BigInteger;

       System.out.println(m.toString());

     }

    JAVA四则运算示例代码

    import java.util.Scanner;
    import java.math.*;
    import java.math.BigInteger;
    
    public class Main {
        public static void main(String args[]) {
            Scanner cin = new Scanner(System.in);
            BigInteger a, b;
            char op;
            String s;
            while (cin.hasNext()) {
                a = cin.nextBigInteger();
                s = cin.next();
                op = s.charAt(0);
                if (op == '+') {
                    b = cin.nextBigInteger();
                    System.out.println(a.add(b));
                } else if (op == '-') {
                    b = cin.nextBigInteger();
                    System.out.println(a.subtract(b));
                } else if (op == '*') {
                    b = cin.nextBigInteger();
                    System.out.println(a.multiply(b));
                } else {
                    BigDecimal a1, b1, eps;
                    String s1, s2;
                    s1 = a.toString();
                    a1 = new BigDecimal(s1);
                    b = cin.nextBigInteger();
                    s2 = b.toString();
                    b1 = new BigDecimal(s2);
                    eps = a1.divide(b1);
                    System.out.println(eps);
                }
            }
            cin.close();
        }
    }

    大数相乘有快速傅里叶求法,仍在学习FFT

    二,数论

    1.素数表

    int pri[MAXN], pris;
    bool notprime[MAXN];
    void init() { //Euler筛法每个合数只会被它最小的质因数筛去,因此时间复杂度为O(N) 
        memset(notprime, 1, sizeof(notprime));
        int i, j;
        for (i = 2, pris = 0; i < MAXN; i++) {
            if (notprime[i])
                pri[pris++] = i;
            for (j = 0; j < pris && i * pri[j] < MAXN; j++) {
                notprime[i * pri[j]] = 0;
                if (i % pri[j] == 0)
                    break;
            }
        }
    }

    2.欧拉函数 1到n-1跟n互质的数的个数

    //1~maxn欧拉函数表
    eu[1] =1;
    for (i = 2; i < maxn; i += 2) 
        if(!eu[i]) {
    for (j = i; j < maxn; j += i){
        if(!eu[j]) eu[j] = j;
        eu[j] = eu[j] / i * (i - 1);
    }
    
    //容斥原理求单个数欧拉函数
    unsigned euler(int x){
        int i, res=x;
        for (i = 2; i < (int)sqrt(x * 1.0) + 1; i++)
            if(x%i==0) {
                res = res / i * (i - 1);
                while (x % i == 0) x /= i; //保证i一定是素数
            }
        if (x > 1) res = res / x * (x - 1);
        return res;
    }
    //素数欧拉性质 phi(pi^ai) = pi^ai - pi^(ai-1)

    3.扩展欧几里德求ax+by=gcd(a,b)

    #define LL long long
    LL exGcd(LL a,LL b,LL &x,LL &y) { //ax+by=gcd(a,b)
        if(b==0) {
            x=1, y=0;
            return a;
        }
        LL temp=exGcd(b,a%b,x,y);
        LL t=x;
        x=y;
        y=t-a/b*y;
        return temp;
    }

    4.乘法逆元

    /*
     * 当要求(a/b)%p的值,且a很大,由于除法没有同余公式,要用乘法逆元改成可同余的相乘
     * 逆元k满足 b*k = 1 (mod p)
     * 即 b*k=p*x+1,把k带入(a*k)%p就得到(a/b)%p
     * 扩展的欧几里德算法求乘法逆元模板
     * (a/b) mod p = ( a*[b与p(互质)乘法逆元]k ) mod p
     */
    /************************************/
    #define LL long long
    LL exGcd(LL a,LL b,LL &x,LL &y) { //ax+by=gcd(a,b)
        if(b==0) {
            x=1, y=0;
            return a;
        }
        LL temp=exGcd(b,a%b,x,y);
        LL t=x;
        x=y;
        y=t-a/b*y;
        return temp;
    }
    LL cal(LL a,LL b) { // "b*k=p*x+1"这里a = "b", y = "k"
        LL x,y;
        exGcd(a,b,x,y);
        x=(x%b+b)%b; //重要
        return x;
    }
    
    /*
     * 模板2,欧拉函数f[p],欧拉定理说明当gcd(a,p)=1,a^f[p]=1 (mod p)
     * 费马小定理的推广 p是素数 a^(p-1)=1 (mod p)
     * b*k%p = 1 = b^(p-1)%p ,则逆元 k = b^(p-2)
     */
    LL pow(LL x, LL y) {
        LL ret = 1;
        while (y) {
            if (y&1) ret=(ret*x)%mod;
            x=(x*x)%mod;
            y>>=1;
        }
        return ret;
    }
    LL inv( LL a ,LL b) {
        return pow(a, b - 2 )%b;
    }

    5.素因子分解

    //prime_factor()传入n, 返回不同质因数的个数
    //f存放质因数,nf存放对应质因数的个数
    //dfs(0,n)求出[1, n]内有多少个数和n不互质
    LL f[MAXN], nf[MAXN];
    int prime_factor(LL n) {
        int cnt = 0;
        for(int i = 0; n > 1 && pri[i] *pri[i]<= n; i++)
            if (n % pri[i] == 0) {
                for (nf[cnt] = 0; n % pri[i] == 0; nf[cnt]++, n /= pri[i]);
                f[cnt++] = pri[i];
            }
        if (n > 1) nf[cnt++] = 1, f[cnt - 1] = n;
        return cnt;
    }
    void dfs(int index, LL n) {
        if (index == cnt) { //枚举完所有素因子
            sta.insert(n); //sta 保存所有因子
            return;
        }
        dfs(index + 1, n);
        for (int i = 0; i < nf[index]; i++) {
            n /= (LL) f[index];
            dfs(index + 1, n);
        }
    }
    LL dfs(int start, LL n) { //容斥原理搜索和n不互质的个数
        LL s = 0;
        for(int i = start;i < cnt;i++)
            s += n/f[i] - dfs(i+1, n/f[i]);
        return s;
    }

    6.求和公式,k = 1..n

    1. sum( k ) = n(n+1)/2

    2. sum( 2k-1 ) = n^2

    3. sum( k^2 ) = n(n+1)(2n+1)/6

    4. sum( (2k-1)^2 ) = n(4n^2-1)/3

    5. sum( k^3 ) = (n(n+1)/2)^2

    6. sum( (2k-1)^3 ) = n^2(2n^2-1)

    7. sum( k^4 ) = n(n+1)(2n+1)(3n^2+3n-1)/30

    8. sum( k^5 ) = n^2(n+1)^2(2n^2+2n-1)/12

    9. sum( k(k+1) ) = n(n+1)(n+2)/3

    10. sum( k(k+1)(k+2) ) = n(n+1)(n+2)(n+3)/4

    12. sum( k(k+1)(k+2)(k+3) ) = n(n+1)(n+2)(n+3)(n+4)/5

     

    三,组合数学

    错排公式递推式 f[1]=0,f[2]=1,f[i] = (i-1)*(f[i-1]+f[i-2])

    如若一个排列式的所有的元素都不在原来的位置上,则称这个排列为错排

    全部抽错概率即全部排错的情况个数除以的全排列个数

    1. C(m,n)=C(m,m-n)

    2. C(m,n)=C(m-1,n)+C(m-1,n-1)

    3. m个物品放到到不同的n个容器中,插板法结果为c(n+m-1,n-1)

    #define MOD 1000000007
    long long c[505][505];
    void Init() {
        for(int i=0;i<=500;i++) {
            c[i][0]=c[i][i]=1;
            for(int j=1;j<i;j++) 
                c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
        }
    }

    容斥原理

    分母是1001的最简分数一共有多少个?

    分析:这一题实际上就是找分子中不能与1001进行约分的数。由于1001=7×11×13,所以就是找不能被7,11,13整除的数。

    解答:1~1001中,有7的倍数1001/7 = 143;有11的倍数1001/11 = 91,有13的倍数1001/13 = 77 ;有7*11=77的倍数1001/77 = 13 ,有7*13=91的倍数1001/91 = 11,有11*13=143的倍数1001/43 = 7.有1001的倍数1个。

    由容斥原理知:在1~1001中,能被7或11或13整除的数有(143+91+77)-(13+11+7)+1=281,从而不能被7、11或13整除的数有1001-281=720(个).也就是说,分母为1001的最简分数有720个。

     

    康托展开

    int first[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    unsigned int factorial[21] = { 1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,1932053504,1278945280,2004310016,2004189184,4006445056,3396534272,109641728,2192834560 };
    unsigned int GetPermutationNum(int permutation[], int len) {
        bool used[11] = { 0 };
        int perInt[11];
        for (int i = 0; i < len; ++i)
            for (int j = 0; j < len; ++j) {
                if (permutation[i] == first[j]) {
                    perInt[i] = j;
                    break;
                }
            }
        unsigned int num = 0;
        for (int i = 0; i < len; ++i) {
            unsigned int n = 0;
            for (int j = 0; j < perInt[i]; ++j) {
                if (!used[j])
                    ++n;
            }
            num += n * factorial[len - i - 1];
            used[perInt[i]] = 1;
        }
        return num;
    }

    Gray码

    这种遍历顺序作为一种编码方式存在,叫做Gray码,发明它主要是为了减少读写磁盘在两个相邻扇区之间的误差问题。

    n阶的Gray码相当于在构造的n维立方体上的Hamilton回路,因为沿着立方体上的边走一步,n维坐标中只会有一个值改变。

    Gray码和Hanoi塔问题等价。Gray码改变的是第几个数,Hanoi塔就该移动哪个盘子。比如,3阶的Gray码每次改变的元素所在位置依次为1-2-1-3-1-2-1,这正好是3阶Hanoi塔每次移动盘子编号。如果我们可以快速求出Gray码的第n个数是多少,我们就可以输出任意步数后Hanoi塔的移动步骤。Gray码的第n个数(从0算起)是n xor (n >> 1)。下面我们把二进制数和Gray码都写在下面,可以看到左边的数异或自身右移的结果就等于右边的数。

    二进制数 Gray码
    000 000
    001 001
    010 011
    011 010
    100 110
    101 111
    110 101
    111 100

  • 相关阅读:
    C# switch-case
    Python学习日记之中文支持
    C++学习笔记(一)之指针
    python CGI 编程实践
    linux 配置 python3 CGI
    PowerShell入门简介
    资源整合,总有你想要的
    python 爬虫之 urllib库
    一天学一个Linux命令:第一天 ls
    DG磁盘分区提示错误
  • 原文地址:https://www.cnblogs.com/updateofsimon/p/3405627.html
Copyright © 2011-2022 走看看