zoukankan      html  css  js  c++  java
  • grandson定理

    用处:求解同余线性方程组

    inv:逆元

    一堆物品

    3个3个分剩2个

    5个5个分剩3个

    7个7个分剩2个

    问这个物品有多少个

    5*7*inv(5*7,  3) % 3  =  1

    3*7*inv(3*7,  5) % 5  =  1

    3*5*inv(3*5,  7) % 7  =  1

    然后两边同乘你需要的数

    2 * 5*7*inv(5*7,  3) % 3  =  2

    3 * 3*7*inv(3*7,  5) % 5  =  3

    2 * 3*5*inv(3*5,  7) % 7  =  2

    令 

    a = 2 * 5*7*inv(5*7,  3)     b = 3 * 3*7*inv(3*7,  5)     c = 2 * 3*5*inv(3*5,  7) 

    那么

    a % 3 = 2    b % 5 = 3    c % 7 = 2  答案就是a+b+c

    因为

    a%5 = a%7 = 0 因为a是5的倍数,也是7的倍数    b%3 = b%7 = 0 因为b是3的倍数,也是7的倍数    c%3 = c%5 = 0 因为c是3的倍数,也是5的倍数

    所以

    (a + b + c) % 3 = (a % 3) + (b % 3) + (c % 3) = 2 + 0 + 0 = 2

    (a + b + c) % 5 = (a % 5) + (b % 5) + (c % 5) = 0 + 3 + 0 = 3

    (a + b + c) % 7 = (a % 7) + (b % 7) + (c % 7) = 0 + 0 + 2 = 2

    每105个就是一个答案(105 = 3 * 5 * 7)

    根据计算,最小的答案等于233,233%105 = 23

    //n个方程:x=a[i](mod m[i]) (0<=i<n)
    LL china(int n, LL *a, LL *m){
        LL M = 1, ret = 0;
        for(int i = 0; i < n; i ++) M *= m[i];
        for(int i = 0; i < n; i ++){
            LL w = M / m[i];
            ret = (ret + w * inv(w, m[i]) * a[i]) % M;
        }
        return (ret + M) % M;
    }
    两两互质代码

    例题:poj 1006

    人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天。一个周期内有一天为峰值,在这一天,人在对应的方面(体力,情感或智力)表现最好。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。

    #include<cstdio>
    typedef long long LL;
    const int N = 100000 + 5;
    void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
        if (!b) {d = a, x = 1, y = 0;}
        else{
            ex_gcd(b, a % b, y, x, d);
            y -= x * (a / b);
        }
    }
    LL inv(LL t, LL p){//如果不存在,返回-1 
        LL d, x, y;
        ex_gcd(t, p, x, y, d);
        return d == 1 ? (x % p + p) % p : -1;
    }
    LL china(int n, LL *a, LL *m){//中国剩余定理 
        LL M = 1, ret = 0;
        for(int i = 0; i < n; i ++) M *= m[i];
        for(int i = 0; i < n; i ++){
            LL w = M / m[i];
            ret = (ret + w * inv(w, m[i]) * a[i]) % M;
        }
        return (ret + M) % M;
    }
    int main(){
        LL p[3], r[3], d, ans, MOD = 21252;
        int cas = 0;
        p[0] = 23; p[1] = 28; p[2] = 33;
        while(~scanf("%I64d%I64d%I64d%I64d", &r[0], &r[1], &r[2], &d) && (~r[0] || ~r[1] || ~r[2] || ~d)){
            ans = ((china(3, r, p) - d) % MOD + MOD) % MOD;
            printf("Case %d: the next triple peak occurs in %I64d days.
    ", ++cas, ans ? ans : 21252);
        }
        
    }
    solve one

    如果两两不保证互质的话

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    typedef pair<LL, LL> PLL;
    PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组 
        LL x = 0, m = 1;
        for(int i = 0; i < n; i ++) {
            LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
            if(b % d != 0)  return PLL(0, -1);//答案不存在,返回-1 
            LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
            x = x + m*t;
            m *= M[i]/d;
        }
        x = (x % m + m ) % m;
        return PLL(x, m);//返回的x就是答案,m是最后的lcm值 
    }
    两两不互质

    例题:poj 2891

    给出k个模方程组:x mod ai = ri。求x的最小正值。如果不存在这样的x,那么输出-1.

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    typedef pair<LL, LL> PLL;
    LL a[100000], b[100000], m[100000];
    LL gcd(LL a, LL b){
        return b ? gcd(b, a%b) : a;
    }
    void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
        if (!b) {d = a, x = 1, y = 0;}
        else{
            ex_gcd(b, a % b, y, x, d);
            y -= x * (a / b);
        }
    }
    LL inv(LL t, LL p){//如果不存在,返回-1 
        LL d, x, y;
        ex_gcd(t, p, x, y, d);
        return d == 1 ? (x % p + p) % p : -1;
    }
    PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组 
        LL x = 0, m = 1;
        for(int i = 0; i < n; i ++) {
            LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
            if(b % d != 0)  return PLL(0, -1);//答案,不存在,返回-1 
            LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
            x = x + m*t;
            m *= M[i]/d;
        }
        x = (x % m + m ) % m;
        return PLL(x, m);//返回的x就是答案,m是最后的lcm值 
    }
    int main(){
        int n;
        while(scanf("%d", &n) != EOF){
            for(int i = 0; i < n; i ++){
                a[i] = 1;
                scanf("%d%d", &m[i], &b[i]);
            }
            PLL ans = linear(a, b, m, n);
            if(ans.second == -1) printf("-1
    ");
            else printf("%I64d
    ", ans.first);
        }
    }
    solve two
  • 相关阅读:
    实验吧_简单的sql注入_1、2、3
    实验吧_天下武功唯快不破&让我进去(哈希长度拓展攻击)
    实验吧_密码忘记了(vim编辑器+代码审计)&天网管理系统(php弱比较+反序列化)
    实验吧_Guess Next Session&Once More(代码审计)
    实验吧_NSCTF web200&FALSE(代码审计)
    实验吧_程序逻辑问题(代码审计)&上传绕过
    实验吧_貌似有点难(php代码审计)&头有点大
    网络安全实验室_上传关writeup
    php文件包含漏洞(input与filter)
    我为什么要写LeetCode的博客?
  • 原文地址:https://www.cnblogs.com/Aragaki/p/8613164.html
Copyright © 2011-2022 走看看