Jeanny
寂兮,寥兮,独立不改,周行而不殆

同余方程
大步小步的求法

// ax = 1 (mod b)
// ax + by = 1
//
// x = x0 + b/gcd(a,b) * k
// y = y0 - a/gcd(a,b) * k
//
// 由于题目中说明一定有解 gcd(a,b) = 1
// x = x0 + b*k
// 如果x>b,mod b 即可
// 因此x最小的正整数解的范围是[0, b)
//
// 构造 x = k * B + t 其中 B = sqrt(b)
// k的范围是 (0, b/B]
// t的范围是 [0, B)
//
// a * (k * B + t)  = 1 (mod b)
// a * k * B + a * t = 1 (mod b)
// 因为a、b最小为2,a*k*B大于1
// 所以:
// a * k * B  + a * t 最小是 b + 1
// 左边两个式子都是大于1的小于b的
// tmp = b+1 - a*k*B%b
// 接下来类似于meet in middle去求解

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
map<long long, int> mp;
ll a,b;
int main(){
    scanf("%lld%lld",&a,&b);
    int B = sqrt(b);
    for(int t = B; t >= 0; t--){
        mp[a * t % b] = t;
    }
    for(int k = 0; k <= b/B; k++){
        ll tmp = (b + 1 - (a * k * B % b))%b;
        if(mp.find(tmp) != mp.end()){
            printf("%lld\n",1ll * k * B + 1ll * mp[tmp]);
            break;
        }
    }
    return 0;
}

exgcd


// ax + by = gcd(a,b)
// bx' + (a%b)y' = gcd(b, a%b)
// ... ...
// kx + 0y = gcd(k, 0)
//
// bx' + (a - a/b*b)y' = gcd(b, a%b)
// 还原
// ay' + b(x' - a/b * y') = gcd(b, a%b)
// ax  + by = gcd(a,b)


// 3 *x  = 1 mod 10
//3 * x + 10 * y = 1
// x = x0 + b/gcd(a,b)*k = x0 + b*k
// y = y0
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
void exgcd(ll a, ll b, ll &x, ll &y){
    if(b == 0){
        x = 1, y = 0;
        return ;
    }
    exgcd(b, a%b, x, y);
    ll tmp = y;
    y = x - a/b * y;
    x = tmp;
}
ll a,b,x,y;
int main(){
    scanf("%lld%lld",&a,&b);
    exgcd(a,b,x,y);
    printf("%lld\n",(x%b+b)%b);
    return 0;
}

荒岛野人

思路:
一开始想到了 Ci + Li * Pi mod n, n是枚举的山洞个数
如果可以想到 Ci + x * Pi != Cj + x * Pj (mod n)
继续得到如果 Ci + x * Pi == Cj + x * Pj (mod n), 求出x则说明n不可行,继续枚举。
如果有解,但是大于min(Li, Lj), 也是可以的。问题得以解决。

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n, c[20], p[20], l[20], mn;
int GCD(int x, int y){
    if(!y) return x;
    return GCD(y, x % y);
}
void exgcd(int a, int b, int &x, int &y){
    if(!b){
        x = 1, y = 0;
        return;
    }
    exgcd(b, a%b, x, y);
    int tmp = y;
    y = x - a/b*y;
    x = tmp;
}
int main(){
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%d%d%d",&c[i], &p[i], &l[i]);
        mn = max(mn, c[i]);
    }
    for(int v = mn; ;v++){
        int fl = 0;
        for(int i = 1; i <= n; i++){
            for(int j = i + 1; j <= n; j++){
                int a = p[i] - p[j], b = v, d = c[j] - c[i], x = 0, y = 0;
                int gcd = GCD(a, b);
                if(d % gcd == 0){//如果有解
                    a = a/gcd, b = b/gcd, d = d/gcd;
                    exgcd(a, b, x, y);
                    b = abs(b);
                    x = ((x * d) % b + b) % b;
                    if(x == 0) x += b;
                    if(x <= min(l[i], l[j])){//如果解<min(l[i], l[j])
                        fl = 1; break;
                    }
                }

            }
            if(fl == 1) break;
        }
        if(!fl){
            printf("%d\n",v);
            return 0;
        }
    }
    return 0;
}

posted on 2022-11-18 10:06  Jeanny  阅读(21)  评论(0)    收藏  举报