同余方程
大步小步的求法
// 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;
}