https://www.luogu.com.cn/problem/P1082
https://blog.youkuaiyun.com/zhjchengfeng5/article/details/7786595
https://blog.youkuaiyun.com/zero_from/article/details/52984044
https://blog.youkuaiyun.com/weixin_44203780/article/details/88873296
https://blog.youkuaiyun.com/destiny1507/article/details/81750874
洛谷 p1082题解 学委
参考自以上链接(相当于是这些文章的拼凑。。。)
同余方程
ax ≡ b (mod n) 即ax和b除以n的余数相同 (ax%n==b%n)
ax≡b (mod n)
ax=b+n*y
ax-n*y=b
换一种写法为 ax + by = c (正负号不重要)
c%gcd(a,b)==0时,ax + by = c有解。
x=x0+b/gcd(a,b)*k y=y0+a/gcd(a,b)*k
所以只要求出一个特解,就能够求出剩余的解;
ax+by = z,z为gcd(a,b)若干倍,所以我们先求解ax+by = gcd(a,b),再将求出的解乘以 z/gcd(a,b)就好了。
一个重大遗留:我们将要求出来的 x,y 仅仅保证满足 ax+by=1,而 x 不一定是最小正整数解。有可能太大,也有可能是负数。x 批量地减去或加上 b,能保证 ax+by=1:
ax + by = 1
ax + by + k×ba - k×ba = 1
a(x+kb)+(y−ka)b=1
显然这并不会把方程中任何整数变成非整数。
2.“加上或减去 bb”不会使 xx 错过任何解。可以这么理解:
因此到最后,如果 x 太小就不断加 b 直到大于等于 0,太大则一直减 b,直到最小正整数解。
直接求模实现更快 x = (x % b + b) % b;
a>b
int exgcd(int a,int b,int &x,int &y){//扩展欧几里得算法
if(b==0){
x=1;y=0;
return a; //到达递归边界开始向上一层返回
}
int g=exgcd(b,a%b,x,y);
int x1 = y,y1 = x-a/b*y;
x = x1;
y = y1;
return g; //得到a b的最大公因数
}
https://vjudge.net/problem/Gym-101512I
#include <bits/stdc++.h>
//#include <iostream>
//#include <cstring>
//#include <string>
//#include <algorithm>
//#include <cmath>
//#include <cstdio>
//#include <queue>
//#include <stack>
//#include <map>
#define pb push_back
#define mp make_pair
#define pi acos(-1.0)
#define ull unsigned long long
#define ll long long
#define sc(x) scanf("%d",&x)
#define fi(a, b) for(int i=a; i<=b; i++)
#define mem(a, b) memset(a, b, sizeof(a))
#define lowbit(x) (x&(-x))
#define mid (l + r) / 2
#define ls pos*2
#define rs pos*2+1
#define ios() ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//int gcd(int a,int b){
// return b==0?a:gcd(b,a%b);
//}
const int maxn=1e2+50;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 9;
using namespace std;
//struct node{
// int hp, dps;
// double rk;
//}s[30];
//bool cmp(node a, node b){
// return a.rk>b.rk;
//}
//vector<int>dp[maxn];
//set<int>p;
//map<string ,int>ma;
ll f[50], e[50];
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;y=0;
return a;
}
ll g=exgcd(b,a%b,x,y);
ll x1 = y,y1 = x-a/b*y;
x = x1;
y = y1;
return g;
}
int main(){
ios();
// int n, m, k, T;
ll n; int T;
e[0]=1;e[1]=0;
f[0]=0;f[1]=1;
for(int i=2; i<50; i++){
f[i]=f[i-1]+f[i-2];
e[i]=e[i-1]+e[i-2];
}
cin>>T;
ll x, y;
while(T--){
cin>>n;
for(int i=49; i>=2; i--){
ll a=e[i], b=f[i];
if(n%__gcd(a,b)==0){
ll g = exgcd(e[i],f[i],x,y);
x*=(n/g);y*=(n/g);
缩小x,y;
方法1:
if(x>y){
ll k=(x-y)/(a+b);
if(x-k*b>y+k*a)k++;
x-=k*b; y+=k*a;
}
else{
ll k=(y-x)/(a+b);
if(x+k*b>y-k*a)k--;
x+=k*b; y-=k*a;
}
方法2:
ll k=(x-y)/(a+b);
x-=k*b; y+=k*a;
if(x>y)x-=b,y+=a;
if(x<=0)continue;
cout<<x<<" "<<y<<endl;
break;
}
}
}
return 0;
}