- ZOJ3609
- ZOJ3593
- POJ1061
- HDU1576
- HDU2669
- UVA12169
ZOJ3609 Modular Inverse
题解
求最小的正逆元,直接用扩展欧几里得就行,注意特殊点,当 ax≡ 1 (mod 1)时。逆元为0,但是要求正逆元,所以要在判断时是 <=0
代码
#include<iostream>
#include<cstdio>
using namespace std;
int exgcd( int a,int b, int &x, int &y )
{
int r = a % b;
int x0, y0, x1, y1;
x0 = 1; y0 = 0;
x1 = 0; y1 = 1;
x = x1, y = y1;
while( r )
{
x = x0 - a / b * x1;
y = y0 - a / b * y1;
x0 = x1;
y0 = y1;
x1 = x;
y1 = y;
a = b;
b = r;
r = a % b;
}
return b;
}
int main()
{
int T, a, b, x, y, d;
scanf( "%d", &T );
while( T -- )
{
scanf( "%d%d", &a, &b );
int d = exgcd( a, b, x, y );
if( d > 1 ) printf( "Not Exist\n" );
else printf( "%d\n", x > 0 ? x : x + b );
}
return 0;
}
ZOJ3593 One Person Game
知识
不定方程ax + by = c的通解
先求出特解x0,y0
通解
x = x0 - ( b / gcd( a, b ) ) * t
y = y0 + ( a / gcd( a, b ) ) * t;
题解
转换为方程式 ax + by + cz = d 求min( |x|+|y|+|z| );
因为 c = a + b;所以可以转化为3个二元不定方程
ax + by = d , by + cz = d, ax + cz = d,所以可以使用扩展欧几里得求ax + by = d
求min(|x|+|y|)
因为 x = x0 - ( b / gcd(a, b) ) * t, y = y0 + ( a / gcd( a, b ) ) * t;
最小值在3个位置 x = 0, y = 0 x = y处
因为是整数,所以 求出每个位置的值tmp后,还要求tmp - 1, tmp + 1,然后再计算最小值,
可能这题的测试数据太弱了。感觉网上很多程序都不对。。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long C;
long long exgcd( long long a,long long b, long long &x, long long &y )
{
long long r = a % b;
long long x0, y0, x1, y1;
x0 = 1; y0 = 0;
x1 = 0; y1 = 1;
x = x1, y = y1;
while( r )
{
x = x0 - a / b * x1;
y = y0 - a / b * y1;
x0 = x1;
y0 = y1;
x1 = x;
y1 = y;
a = b;
b = r;
r = a % b;
}
return b;
}
long long solve( long long m, long long n )
{
long long x0, y0, goal, tmp, xx, yy;
long long d = exgcd( m, n, x0, y0 );
if( C % d ) return -1;
x0 *= ( C / d );
y0 *= ( C / d );
long long kx = x0 / n * ( -1 );
long long mm = m / d;
long long nn = n / d;
//case 1
tmp = x0 / nn ;
xx = x0 - tmp * nn;
yy = y0 + tmp * mm;
goal = abs( xx ) + abs ( yy );
tmp ++;
xx = x0 - tmp * nn;
yy = y0 + tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
tmp -= 2;
xx = x0 - tmp * nn;
yy = y0 + tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
//case 2
tmp = y0 / mm;
xx = x0 + tmp * nn;
yy = y0 - tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
tmp ++;
xx = x0 + tmp * nn;
yy = y0 - tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
tmp -= 2;
xx = x0 + tmp * nn;
yy = y0 - tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
//case 3
tmp = abs( x0 - y0 ) / abs( nn + mm );
xx = x0 - tmp * nn;
yy = y0 + tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
tmp ++;
xx = x0 - tmp * nn;
yy = y0 + tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
tmp -= 2;
xx = x0 - tmp * nn;
yy = y0 + tmp * mm;
goal = min( abs( xx ) + abs ( yy ), goal );
return goal;
}
int main()
{
int T;
long long a, b, c, A, B;
scanf( "%d", &T );
while( T -- )
{
scanf( "%lld%lld%lld%lld", &A, &B, &a, &b );
c = a + b;
C = A - B;
long long Min = solve( a, b );
Min = min( Min, solve( a, c ) );
Min = min( Min, solve( b, c ) );
printf( "%lld\n", Min );
}
return 0;
}