进制范围
一、基本数据类型的特点,位数,最大值和最小值。
1、
short -32768-32767
基本类型:short 二进制位数:16
包装类:java.lang.Short
最小值:Short.MIN_VALUE=-32768 (-2的15此方)
最大值:Short.MAX_VALUE=32767 (2的15次方-1)
2、
2147483647
基本类型:int 二进制位数:32
包装类:java.lang.Integer
最小值:Integer.MIN_VALUE= -2147483648 (-2的31次方)
最大值:Integer.MAX_VALUE= 2147483647 (2的31次方-1)
3、
基本类型:long 二进制位数:64
包装类:java.lang.Long
最小值:Long.MIN_VALUE=-9223372036854775808 (-2的63次方)
最大值:Long.MAX_VALUE=9223372036854775807 (2的63次方-1)
4、
基本类型:float 二进制位数:32
包装类:java.lang.Float
最小值:Float.MIN_VALUE=1.4E-45 (2的-149次方)
最大值:Float.MAX_VALUE=3.4028235E38 (2的128次方-1)
5、
基本类型:double 二进制位数:64
包装类:java.lang.Double
最小值:Double.MIN_VALUE=4.9E-324 (2的-1074次方)
最大值:Double.MAX_VALUE=1.7976931348623157E308 (2的1024次方-1)
进制可写位数
二、经实践证明,在代码中,能够写的位数。
1、首先是整型
int和long只能写10个数字,short只能写5个数字,多了就会报错。
int h=1234567890;
long w=1234567890;
short s=12345;
如果此时我在它们每个上面再加上一个数字,就会:
2、其次浮点
float的小数点后6位,double的小数点后16位。
float m=123.45566778465651454545f;
double n=3.1234567890123456789;
1.从定义上来看
int 是基本类型,直接存数值(类似的还有float、double、String、char)
Integer是对象,用一个引用指向这个对象(类似的有Float、Double、String)
2.从复杂度来看,
Java 中的数据类型分为基本数据类型和复杂数据类型
int 是前者;Integer 是后者(也就是一个类)
3.初始化的方式不同
int i =1;
Integer i= new Integer(1);//integer 是一个类
int 是基本数据类型(面向过程留下的痕迹,不过是对java的有益补充);Integer 是一个类,是int的扩展,定义了很多的转换方法
注意:类似的还有:float Float;double Double;String等,其中String较为特殊,基本类型和复杂类似关键字相同。
例如,当需要往ArrayList,HashMap中放东西时,
像int,double这种内建类型是放不进去的,因为容器都是装 object的,
这是就需要这些内建类型的外覆类了。Java中每种内建类型都有相应的外覆类。
高斯消元法
输出结果为3种情况:
1.无解,
2.有唯一解
3.有无穷多解。
步骤:
代码
注意:
java中的小数保留的方法:
BigDecimal b = new BigDecimal(d);
DecimalFormat decimalFormat = new DecimalFormat("0.00#");
String strVal = decimalFormat.format(b);
1.先使用BigDecimal将double数据转换b
2.使用DecimalFormat自己定义一种结构。 new DecimalFormat("0.00#")
3.用定义好的结构将之前的进行转换b。
package 数学知识;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Scanner;
public class 高斯消元求方程解 {
static int N = 10010;
static double[][] g = new double[N][N];
//关于浮点数一定要进行比较,得出最小的值
static double eps =1e-6;//10^-6,比他小为0
static int n;
//第一行包含整数 n。
//接下来 n 行,每行包含 n+1 个实数,表示一个方程的 n 个系数以及等号右侧的常数。
public static void swap(double x, double y){
double tmp = x;
x = y;
y = tmp;
}
public static int gauss(double[][] g){
//行列
int r,c;
//找每一列里最大的哪一个值的那一行往上移动,交换位置
for(r=0,c=0;c<n;c++){
int t = r;//先赋初值
//据说是因为找最大的那一行精度会更准
for(int i=r;i<n;i++){
if(Math.abs(g[i][c])>Math.abs(g[t][c])){
//说明绝对值最大的需要进行更换
t = i;
}
}
//经过循环之后已经找到了最大值的那一行,判断判断是否为0,不为0用这一行进行消元
if(Math.abs(g[t][c])<eps) continue;;
//如果为0,跳出循环,如果不为0,则进行调整位置
//调整位置时注意,这一行的每列元素都需要调整。
for(int i=c;i<n+1;i++){
swap(g[t][i],g[r][i]);
}
//交换完成
//将系数变为1
for(int i=n;i>=c;i--){
//最大值已经在最上面了,所以进行变为1
g[r][i] = g[r][i]/g[r][c];//从最后一列的第一行的数据开始的
}
//消元
for(int i=r+1;i<n;i++){
//判断是否wei0
if(Math.abs(g[i][c]) >eps){
//如果这个数据不为0,再进行消为0
for(int j=n;j>=c;j--){//每列的元素也要进行变化
g[i][j] = g[i][j] - g[r][j]*g[i][c];
}
}
}
r++;
}
if(r<n){
//无解或者无穷解。
for(int i=r;i<n;i++){
if(Math.abs(g[i][n])>eps) return 2;
}
return 1;
}
//就剩唯一解
for(int i= n-1;i>=0;i--){
for(int j=i+1;j<n;j++){
g[i][n] = g[i][n]- g[j][n]*g[i][j];
}
}
return 0;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
//接收数据
for(int i=0;i<n;i++){
for(int j=0;j<n+1;j++){
g[i][j] = sc.nextDouble();
}
}
//g已经有初值
int t = gauss(g);
if(t==0){
for(int i=0;i<n;i++) {
double d = g[i][n];
BigDecimal b = new BigDecimal(d);
DecimalFormat decimalFormat = new DecimalFormat("0.00#");
String strVal = decimalFormat.format(b);
System.out.println(strVal);
}
}
else if(t==1) System.out.println("Infinite group solutions");
else System.out.println("No solution");
}
}
求组合数1-(数字小)加法计数原理
数据范围
1≤n≤10000,
1≤b≤a≤2000
总结说是查表法
代码:
注意:
1.只有下三角,因为上三角数据不合理。
2.组合数累加原理。
package 数学知识;
import java.io.*;
import java.util.Scanner;
public class 求组合数12 {
static int mod =1000000007;
static int N = 2020;
static long[][] f = new long[N][N];
public static void Cmod(){
//初始化
for(int i=0;i<=2000;i++){//a
for(int j=0;j<=i;j++){
if(j==0) f[i][j] = 1;
else f[i][j] = (f[i-1][j-1]+f[i-1][j])%mod;
}
}
}
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
int n = Integer.valueOf(reader.readLine());
//Scanner sc = new Scanner(System.in);
//int n = sc.nextInt();
while (n-->0){
String[] s = reader.readLine().split(" ");
int a = Integer.valueOf(s[0]);
int b = Integer.valueOf(s[1]);
Cmod();
System.out.println(f[a][b]);
}
}
}
组合数2-逆元+费马-(数1-100000)
1≤n≤10000,
1≤b≤a≤10^5
1.数据数变大,预处理方式不同,也是采用查表法。
1.一个是逆元表,infact【】
2.一个是阶乘表fact【】
b!-1 = (b-1!b)-1 = (b-1)!-1b-1
b-1 = b(109)+5=b-1!-1*b(mod-2)
把除法换成乘法。
1.快速幂
2.费马定义
3.输出
注意:先(long())在int可以保证数据不丢失
代码:
package 数学知识;
import java.io.*;
import java.util.Scanner;
public class 求组合数23 {
//先long在int数据不会少
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static int N = 1000007;
static int p = 1000000007;
static int[] fact = new int[N];
static int[] infact = new int[N];
public static int qui(int a,int b, int p){
long res= 1;
while (b!=0){
if((b&1)==1) res = res*a%p;
b = b>>1;
a =(int) ((long)a*a%p);
}
return (int)res;
}
public static void feim_zuhe(){
fact[0] = infact[0]=1;
for(int i=1;i<=100000;i++){
fact[i] = (int)( (long) fact[i-1]*i %p);
infact[i] = (int)( (long) infact[i-1]*qui(i,p-2,p)%p);
}
}
public static void main(String[] args) throws IOException {
int n = Integer.valueOf(reader.readLine());
while (n-->0){
String[] s = reader.readLine().split(" ");
int a = Integer.valueOf(s[0]);
int b = Integer.valueOf(s[1]);
feim_zuhe();
int ans =(int) ((long)fact[a]*infact[b]%p*infact[a-b]%p);
System.out.println(ans);
}
}
}
求组合数3-数超级大,lucas定理
1≤n≤20,
1≤b≤a≤10^18,
1≤p≤10^5,
每个数钞机无敌大,使用lucas
lucas定理的证明
高精度组合数-bigInteger
据范围较大超级大且要乘除所以想当然的使用高精
分解N!的质因子那理所当然
M!的质因子也能分解,
那这么说的话(N-M)!的质因子也一定能分解。
看到这应该也看明白了,C(N,M)=N!/M!/(N-M)!
求出质因子的用途就很想当然了我们可以把它的所有质因子乘起来这样既可得到最终答案。
而直接求出上面式子有些许困难我们不如直接求出N!的质因子接着减去这些除数的质因子。
这样就得出了答案所有的质因子。
1.筛质因子(N!,M!,(N-M)!)
2.上下相减因子求出质数的次数
3.盛器来
算出阶乘的质因子的次数:
例如
8!=1234567*8
本身应该有2里1个,4里面有2个,6里面有1个,8里面有3个
1+2+1+3 = 7。
利用公式:
8/2=4
8/4=2
8/8=1
=7
代码:
//最后高精度的转换一定要先进行初始化原始数
//线性筛的熟
package 数学知识;
import java.math.BigInteger;
import java.util.Scanner;
public class 求组合数44 {
//筛质数
//求个数,相减
//累乘。
static int N =5010;
static int[] primes = new int[N];
static boolean[] st = new boolean[N];
static int num;//记录质数
static int[] sum = new int[N];
public static void get_primes(int n){
for(int i=2;i<=n;i++){
if(st[i] == false) primes[num++] = i;
for(int j=0;primes[j]*i<=n;j++){
st[primes[j]*i]=true;
if(i%primes[j]==0) break;
}
}
}
//阶乘的质因子的次数
public static int get(int a,int p){
int cnu = 0;
while (a!=0){
cnu = cnu+a/p;
a = a/p;
}
return cnu;
}
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
//首先筛质数
get_primes(a);
//因为啊a>b
for(int i=0;i<num;i++){
sum[i] = get(a,primes[i])-get(b,primes[i])-get(a-b,primes[i]);
}
//现在的质因子次数就是剩下的
//高精度计算
BigInteger res = BigInteger.valueOf(1);
for(int i=0;i<num;i++){//p
BigInteger p = BigInteger.valueOf(primes[i]);
for(int j=0;j<sum[i];j++){
res = res.multiply(p);
}
}
System.out.println(res);
}
}
卡特数
根据范围选方法:
C(2n n)
= 2n!/n!(2n-n)!
= 2n!/n!n!
= (n+1)…(2n)/n!=(n+1)(n+2)(n+3)…2n/(123…n)/n+1
1.每一条cong(0,0)-(5,7)-都会走到
代码:
package 数学知识;
import java.util.Scanner;
public class 满足条件的01序列 {
static int p = 1000000007;
public static long qui_mi(int a,int b,int p){
long res = 1;
while (b!=0){
if((b&1)==1)res = res *a %p;
b = b>>1;
a =(int) ((long)a*a%p);
}
return res;
}
public static void main(String[] args) {
Scanner sc= new Scanner(System.in);
int n = sc.nextInt();
//上面
long res = 1;
for(int i=2*n;i>=n+1;i--){
res = res*i%p;
}
//下面
//将除法变为乘法,使用逆元的方式进行
for(int i=1;i<=n;i++){
res = res * qui_mi(i,p-2,p)%p;
}
//n+1
res = res*qui_mi(n+1,p-2,p)%p;
System.out.println(res);
}
}