五指山||C 循环(扩展欧几里得)

1299. 五指山

五指山
在这里插入图片描述
思路
1.扩展欧几里得 acwing 877
在求最大公约数同时求得一组 x,y满足gcd(a, b) = a * x + b * y
\(\gcd(a,\ b) = gcd(b,\ a\ \%\ b)\)
\(ax+by = b*x0 + (a \% b)\ *y0\)
由于 \(a\%b = a - \lfloor\frac{a}{b}\rfloor\ *b\)
整理得 \(ax+by = a*y0 + b\ *(x0-\lfloor\frac{a}{b}\rfloor\ *y0)\)
即递归根据下一层得x,y求得当前层得x,y
\(x=y0\)
\(y=x0-\lfloor\frac{a}{b}\rfloor\ *y0\)
2.
\(a\ *x0+b\ *y0=gcd(a,b)=d\)
扩展欧几里得求得x0,y0
x,y满足\(x=x0±k\ *\frac{b}{d}\)\(y=y0∓k\ *\frac{a}{d}\)
3.
本题可抽象出\(x+ad≡y(mod\ n)\)
\(x+ad=y+bn\) 此处的a和b为变量
整理得\(ad-bn=y-x\)
由扩展欧几里得\(ad-bn=gcd(d,\ n)\) 要使得a有解需要满足\(y-x\)\(gcd(d, n)\)的倍数
题目求a的最小值,由
2.
\(a=a0+k\ *\frac{n}{gcd(d,\ n)}\)
\(a0=a\ mod\ \frac{n}{gcd(d,\ n)}\) 为所求值

样例输入:

2
3 2 0 2
3 2 0 1

样例输出:

1
2

代码:

#include<iostream>
using namespace std;

typedef long long LL;

LL exgcd(LL a, LL b, LL &x, LL &y)
{
    if(!b)
    {
        x = 1, y = 0;
        return a;
    }
    
    LL e, x0, y0;
    e = exgcd(b, a % b, x0, y0);
    x = y0, y = x0 - a / b * y0;
    
    return e;
}

int main()
{
    int T;
    cin >> T;
    while(T -- )
    {
        LL n, d, a, b, x, y;
        cin >> n >> d >> x >> y;
        LL e = exgcd(d, n, a, b);
        if((y - x) % e) cout << "Impossible" << endl;
        else
        {
            a = (a * ((y - x) / e));
            n /= e;
            cout << (a % n + n) % n<< endl;  //处理负数
        }
        
    }
    
    return 0;
}

 

1301. C 循环

C 循环
在这里插入图片描述
样例输入:

3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0

样例输出:

0
2
32766
FOREVER

代码:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long LL;

LL exgcd(LL a, LL b, LL &x, LL &y)  //拓展欧几里得算法 ax + by = d
{
    if (b == 0)  //边界情况
    {
        x = 1, y = 0;
        return a;
    }
    LL d = exgcd(b, a % b, y, x);  //y*b + x(a mod b) = d;
    y -= a / b * x;  //公式推系数(下方图一)
    return d;
}

int main()
{
    LL a, b, c, k;

    while (cin >> a >> b >> c >> k, a || b || c || k)  //逗号表达式
    {
        LL x, y;  //系数  公式:x*C - y2^k = B - A
        LL z = 1ll << k;  //为了方便,公式:x*C - y*z = B - A
        LL d = exgcd(c, z, x, y); 
        if ((b - a) % d)  //有没有解取决于B - A是否能整除d
            cout << "FOREVER" << endl;  //求余不为0,一定无解
        else  //否则一定有解
        {
            x *= (b - a) / d;  //因为等式右边原本是d,现在是(B - A), 所以等式右边x, y乘上(B-A)/d
            z /= d;  //根据公式,x = x0 + k*(b/d),这里的b就是z,此时所有的解x和x0的差,都是z的倍数
            cout << (x % z + z) % z << endl;  //x的最小非负整数解,就是x0 mod z, c++中取模可能是负数
        }
    }

    return 0;
}

 

posted @ 2022-04-01 00:25  panse·  阅读(215)  评论(0)    收藏  举报