五指山||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;
}

浙公网安备 33010602011771号