扩展欧几里德 poj1061 青蛙的约会
扩展欧几里德很经典。可是也有时候挺难用的。一些东西一下子想不明确。。
于是来了一个逆天模板。。仅仅要能列出Ax+By=C。就能解出x>=bound的一组解了~
LL exgcd(LL a, LL b, LL &x, LL &y) { if(b == 0) { x = 1; y = 0; return a; } LL r = exgcd(b, a % b, x, y); LL t = y; y = x - a / b * y; x = t; return r; } /*能够得到x>=bound时的x和y,返回true表示有解 否则无解,我仅仅想问这个模板无脑调用有木有~ 可是不同的题目特判不同,有的地方记得还是特判,比方a和b的正负和是否为0~*/ bool solve(LL a, LL b, LL c, LL bound, LL &x, LL &y) { LL xx, yy, d = exgcd(a, b, xx, yy); if(c % d) return false; xx = xx * c / d; yy = yy * c / d; LL t = (bound - xx) * d / b; x = xx + b / d * t; if(x < bound) { t++; x = xx + b / d * t; } y = yy - a / d * t; return true; }
对于这道题,,我们能得出
A=n-m,B=L,C=x-y
注意A的正负性和是否为0。即可了。然后直接套模板 。以下就是个套模板的样例
#include<map> #include<set> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<string> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #include<functional> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MX = 3e4 + 5; LL exgcd(LL a, LL b, LL &x, LL &y) { if(b == 0) { x = 1; y = 0; return a; } LL r = exgcd(b, a % b, x, y); LL t = y; y = x - a / b * y; x = t; return r; } /*能够得到x>=bound时的x和y,返回true表示有解 否则无解,我仅仅想问这个模板无脑调用有木有~ 可是不同的题目特判不同,有的地方记得还是特判,比方a和b的正负和是否为0~*/ bool solve(LL a, LL b, LL c, LL bound, LL &x, LL &y) { LL xx, yy, d = exgcd(a, b, xx, yy); if(c % d) return false; xx = xx * c / d; yy = yy * c / d; LL t = (bound - xx) * d / b; x = xx + b / d * t; if(x < bound) { t++; x = xx + b / d * t; } y = yy - a / d * t; return true; } int main() { LL x, y, m, n, L; LL A, B, C, X, Y; while(~scanf("%I64d%I64d%I64d%I64d%I64d", &x, &y, &m, &n, &L)) { A = n - m; B = L; C = x - y; if(A == 0) { //使用solve唯一的特判放在外面 printf("Impossible\n"); continue; } if(A < 0) A = -A, C = -C; //保证A和B都是正数 if(solve(A, B, C, 0, X, Y)) { //得到的x会>=1,由于不可能是0,并且也必需要非负嘛,理论上0和1都一样 printf("%I64d\n", X); //对,,就是这样,。做完了。 } else { printf("Impossible\n"); } } return 0; }