高精度计算
Java提供了java.math.BigInteger和java.math.BigDecimal实现大整数和大实数运算。
·常用属性
public static final BigInteger ONE
表示BigInteger的1
public static final BigInteger ZERO
表示BigInteger的0
public static final BigInteger Ten
表示BigInteger的10
//操作
BigInteger zero = BigInteger.ZERO;//0
BigInteger one = BigInteger.ONE;//1
BigInteger ten = BigInteger.TEN;//10
•运算
int n=5;
//add(); 大整数相加
BigInteger a=new BigInteger(“10”);
BigInteger b=new BigInteger(“20”);
BigInteger c1 = a.add(b);
//subtract(); 相减
BigInteger c2 = a.subtract(b);
//multiply(); 相乘
BigInteger c3 = a.multiply(b);
//divide(); 相除取整
BigInteger c4 = a.divide(b);
//remainder(); 取余
BigInteger c5 = a.remainder(b);
//pow();
BigInteger c6 = a.pow(n);
//abs(); 绝对值
BigInteger c7 = a.abs();
//negate(); 取反数
BigInteger c8 = a.negate();
//max();
BigInteger c9 = a.max(b);
//min();
BigInteger c10 = a.min(b);
//punlic int comareTo(BigInteger val);
int c13 = a.compareTo(b);
//boolean equals(); 是否相等
int c14 = a.equals(b);
·类型转换
//valueOf()将参数转化为制定的类型,这里指转化为BigInteger类型
int a=15;
BigInteger b=BigInteger.valueOf(a);//b=15
String c="123";
BigInteger d=BigInteger.valueOf(c);//d=123
//转换为十进制字符串
String c1=a.toString();
//转换为b进制字符串
String c2=a.toString(b);
//转换为int
int c3=a.intValue();
//转换为float
float c4=a.floatValue();
//转换为double
double c5=a.doubleValue();
数论
1.模运算
1.a mod b=a%b;(0 <= a mod m <= m-1)
加:(a+b)mod m=((a mod m)+(b mod m))mod m
减:(a-b)mod m=((a mod m)-(b mod m))mod m
乘:(ab)mod m=((a mod m)(b mod m))mod m
//除法不可用
2.逆元与除法取模
设b的逆元是k
(a/b)mod m=((a/b)mod m)((bk)mod m)=(a/b* b* k)mod m=(a*k)mod m
2.gcd与lcm
·最大公约数
//辗转相除法(欧几里得算法)
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
//C++内置函数
std::__gcd(a,b)
·最小公倍数
两数之积除以它的最大公约数
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
3.扩展欧几里得算法
·设二元一次方程为ax+by=n,只有当n为gcd(a,b)的倍数时才有整数解。
通解为:x=x0+(b/gcd(a,b))t
y=y0-(a/gcd(a,b))t
t为任意实数
·ax+by=gcd(a,b),求x0与y0。
推导:ax1+by1=gcd(a,b)
bx2+(a%b)y2=gcd(b,a%b)
所以ax1+by1=bx2+(a%b)y2
又因为a%b=a-(a/b)*b
所以ax1+by1=ay2+b(x2-(a/b)*y2)
递推公式:
x1=y2
y1=x2-(a/b)y2
void extend_gcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1,y=0;
return;
}
extend_gcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
}
举个例子:4x+6y=8
即extend_gcd(4,6,x,y)
extend_gcd(6,4%6=4,x,y)
extend_gcd(4,6%4=2,x,y)
extend_gcd(2,4%2=0,x,y)
b=0,x=1,y=0
·t=1,x=0,y=1-(4/2) * 0=1
·t=0,x=1,y=0-(6/4) * 1=-1
·t=-1,x=-1,y=1-(4/6) * (-1)=1
所以x=-1,y=1。
·求ax+by=n的整数解:判断(gcd(a,b)%n=0)、求x0与y0、特解为
x=x0 * n/gcd(a,b)
y=y0 * n/gcd(a,b)
4.同余与逆元
·同余定义:如果a mod m=b mod m,则a与b对于m同余,m为同余的模。
(或m|(a-b)即a-b是m的整数倍。即,如果两个整数a、b,它们除以自然数m的余数相同,那么它们的差a-b是m的倍数。)
记为:a≡b(mod m)
·逆元定义:ax≡1(mod m)的一个解x,称x为a模m的逆。(x不唯一且非负)
简单说就是a*x%m==1
int mod_inverse(int a,int m)
{
int x,y;
extend_gcd(a,m,x,y);
return(m+x%m)%m;//x可能为负数
}
·ax+my=b解x:
先判断有无解:gcd(a,m)能整除b则有解。
通过a’a≡1(mod m)求a’,也就是求a模m的逆。
然后x≡a’b(mod m),求得x。
特解为x=a’b,然后代入方程求y。
总结一下:
定理一:如果d = gcd(a, b),则必能找到正的或负的整数k和l,使 d = a*x+ b*y。
定理二:若gcd(a, b) = 1,则方程ax ≡ c (mod b)在[0, b-1]上有唯一解。
定理三:若gcd(a, b) = d,则方程ax ≡ c (mod b)在[0, b/d - 1]上有唯一解。
其他博主的完美定理证明
·有关求最小非负整数解x的问题:
由定理三可知,x在[0,b/d-1]上唯一,令r=b/d,即x在[0,r-1]上唯一,可通过x=(x%r+r)%r求最小非负整数解x。
因为x%r可能为负数,在[-(r-1),0]范围内,正值在[0,r-1]范围内,加上r就保持在[1,2r-1]范围内,再取余r就在[0,r-1]范围内了。
例题
POJ1061青蛙的约会
未完…