算法之数学,数论基础 从入门到入坑 完整版

1,巧用进制

变种3进制

solution:
如二进制:
1011 为11 表示:取 不取 取 取。
将其运用到三进制中即可
在这里插入图片描述

package 学习哔哩哔哩;
//2021年4月1日上午8:58:47
//writer:apple
import java.util.*;
import java.io.*;
public class 变种3进制 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner s=new Scanner(System.in);
		int n=s.nextInt();
		String n3=Integer.toString(n, 3);//转成三进制,用字符保存
		char b[]=new StringBuilder(n3).reverse().toString().toCharArray();//进行翻转 成为升序
		List<Integer> ans=new ArrayList<>();
		for(int i=0;i<b.length;i++)
		{
			if(b[i]=='2')
			{
				ans.add(-1);
				if(i==b.length-1)
				{
					ans.add(1);
				}
				else b[i+1]++;
				
			}
			else if(b[i]=='3')
			{
				ans.add(0);
				if(i==b.length-1)
				{
					ans.add(1);
				}
				else b[i+1]++;
			}
			else {//为1 和0
				ans.add(b[i]-'0');
			}
		}
		for(int i=0;i<ans.size();i++)
		{
			int a=(int) (ans.get(i)*Math.pow(3,ans.size()-i-1));
			System.out.print(a+" ");
		}
	}

}

2,Nim游戏

是一个最后取物品为胜者的游戏。()
Alice先手。Bob后手
在这里插入图片描述
solution:
对每堆石子做异或运算。
结果非0,先手胜(Alice获胜,因为他先手可以让局面变成0)
结果为0,后手胜。

public class Nim {

	static int n;
	static int a[];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner s=new Scanner(System.in);
		n=s.nextInt();
		a=new int[n];
		for(int i=0;i<n;i++)
		{
			a[i]=s.nextInt();
		}
		int ans=solve();
		if(ans>0) System.out.println("Alice");
		else System.out.println("Bob");
	}
	private static int solve() {
		// TODO Auto-generated method stub
		int res=0;
		for(int i=0;i<n;i++)
		{
			res^=a[i];
		}
		return res;
	}
}

阶梯Nim博弈:POJ1704

//2021年4月1日下午6:05:01
//writer:apple
import java.util.*;
import java.io.*;
public class Main{
	
	static int n;
	static int a[];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner s=new Scanner(System.in);
		n=s.nextInt();
		for(int i=0;i<n;i++)
		{
			int nn=s.nextInt();
			a=new int[nn];
			for(int j=0;j<nn;j++)
			{
				a[j]=s.nextInt();
			}
			boolean ans=solve();
			if(ans) System.out.println("Georgia will win");//先手赢
			else System.out.println("Bob will win");
		}

}
	private static boolean solve() {
		// TODO Auto-generated method stub
		int len=a.length;
		int res=0;
		Arrays.sort(a);
		if((len&1)==1)
		{
			for(int i=0;i<len;i=i+2)
			{
				if(i==0)
				{
					res^=(a[i]-1);
				}
				else {
					res^=(a[i]-a[i-1]-1);
				}
			}
		}
		else {
			for(int i=1;i<len;i=i+2)
			{
					res^=(a[i]-a[i-1]-1);
			}
		}
		return res==0?false:true;
	}
}

取球博弈

两个人玩取球的游戏。
一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目。
如果无法继续取球,则游戏结束。
此时,持有奇数个球的一方获胜。
如果两人都是奇数,则为平局。

假设双方都采用最聪明的取法,
第一个取球的人一定能赢吗?
试编程解决这个问题。

输入格式:
第一行3个正整数n1 n2 n3,空格分开,表示每次可取的数目 (0<n1,n2,n3<100)
第二行5个正整数x1 x2 … x5,空格分开,表示5局的初始球数(0<xi<1000)

输出格式:
一行5个字符,空格分开。分别表示每局先取球的人能否获胜。
能获胜则输出+,
次之,如有办法逼平对手,输出0,
无论如何都会输,则输出-

例如,输入:
1 2 3
1 2 3 4 5

程序应该输出:

  • 0 + 0 -

再例如,输入:
1 4 5
10 11 12 13 15

程序应该输出:
0 - 0 + +

再例如,输入:
2 3 5
7 8 9 10 11

程序应该输出:

  • 0 0 0 0

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms

package 第七届;
//2021年4月5日下午10:29:42
//writer:apple
import java.io.*;
import java.util.*;
import java.math.*;
public class 取球博弈 {

	static int a[]=new int[3];
	static int x[]=new int[5];
	static char ans[]=new char[5];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner s=new Scanner(System.in);
		//while(s.hasNext())
		//{
			for(int i=0;i<3;i++) a[i]=s.nextInt();
			for(int i=0;i<5;i++) x[i]=s.nextInt();
			StringBuilder ans=new StringBuilder();
			for(int i=0;i<5;i++)
			{
				int ann=f(x[i],0,0,true);
				if(ann==2) ans.append("+ ");
				else if(ann==1) ans.append("0 ");
				else ans.append("- ");
			}
			System.out.println(ans.toString());
				
		//}
		
	}
	private static int f(int N, int me, int he, boolean isme) {
		// TODO Auto-generated method stub
		int mina=a[0];
		for(int i=0;i<3;i++) mina=Math.min(mina,a[i]);
		if(N<mina)
		{
			if((me&1)==1&&(he&1)!=1) return 2;
			else if((me&1)!=1&&(he&1)==1) return 0;
			else return 1;
		}
		if(isme)
		{
			int max=0;
			for(int i=0;i<3;i++)
			{
				if(N>=a[i])
				max=Math.max(max,f(N-a[i],me+a[i],he,false));
			}
			return max;
		}
		else {
			int min=2;
			for(int i=0;i<3;i++)
			{
				if(N>=a[i])
				min=Math.min(min,f(N-a[i],me,he+a[i],true));
			}
			return min;
		}
		
	}

}

3,必备求和公式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4,欧几里得算法及其扩展

欧几里得算法就是辗转相除法
public statici int gcd(int m,int n)
{
if(n==0)return m;
return gcd(n,m%n);
}
贝祖等式:在这里插入图片描述

5,模运算

求余为取模。
(a+b)%m==(a%m+b%m)%m

(
(ab)%m==(a%mb)%m 但不等于(a%m)*(b%m)
在这里插入图片描述

6,素数

考察质因数:

判断是否是素数

public static boolean isprime(int x)
	{
		if(x==1) return false;
		for(int i=2;i<=Math.sqrt(x);i++)
		{
			if(x%i==0) return false;
		}
		return true;
	}

分解质因数

public class 分解质因数 {

	static int n;
	static Map<Integer,Integer> m=new HashMap<>();//存放质因数和对应次数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner s=new Scanner(System.in);
		n=s.nextInt();
		solve(n);
		
		StringBuilder sb=new StringBuilder();
		for(Map.Entry<Integer, Integer> entry:m.entrySet())
		{
			int k=entry.getKey();
			int v=entry.getValue();
			while(v-->0)
			{
				sb.append("*"+k);
			}
		}
		System.out.println(sb.substring(1));
	}
	public static boolean isprime(int x)
	{
		if(x==1) return false;
		for(int i=2;i<=Math.sqrt(x);i++)
		{
			if(x%i==0) return false;
		}
		return true;
	}
	private static void solve(int n) {
		// TODO Auto-generated method stub
		for(int i=2;i<=Math.sqrt(n);i++)
		{
			while(isprime(i)&&n%i==0)
			{
				Integer val=m.get(i);
				if(val==null)
				{
					m.put(i, 1);
				}
				else m.put(i,val+1);
				n/=i;
			}
		}
	}

}

7,求解对数

Math.log(x):以e为底 x的对数
Math.log(x)/Math.log(d):以d为底 x的对数

8,素数定理

从不大于n的自然数随机选一个,它是素数的概率大约是1/(lnn)
意思就是:在1-x中的素数个数约为:x/(lnx)个

求解第n个素数:

1,运用素数定理,确定这个素数的范围
2,大到小求解

import java.util.*;
public class 求第x个素数 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner s=new Scanner(System.in);
		int n=s.nextInt();
		int maxx=sushudingli(n);//所以第n个素数在[2,maxx]中找
		while(true)
		{
			if(isprime(maxx)) break;
			maxx--;
		}
		System.out.println(maxx);
	}

	private static int sushudingli(int n) {
		// TODO Auto-generated method stub
		int x=2;
		while(x/Math.log(x)<n)
		{
			x++;
		}
		return x;
	}
	public static boolean isprime(int x)
	{
		if(x==1) return false;
		for(int i=2;i<=Math.sqrt(x);i++)
		{
			if(x%i==0) return false;
		}
		return true;
	}


}

9,快速幂运算

private static int poww(int i, int j) {
		// TODO Auto-generated method stub
		
		int ans=1;
		while(j!=0)
		{
			if((j&1)==1)
			{
				ans*=i;
			}
			i=i*i;
			j>>=1;
		}
		return ans;
	}

10,矩阵快速幂

在这里插入图片描述

两矩阵能相乘要求:第一个col等于第二个row。
在这里插入图片描述
适用于求解有递推公式的f(n),如第n个斐波那契数
解法和快速幂一样。

求某矩阵的n次方

import java.io.*;
import java.util.*;
public class 矩阵快速幂 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner s=new Scanner(System.in);
		int hl=s.nextInt(); int ci=s.nextInt();//求矩阵的ci次方
		int rec[][]=new int[hl][hl];
		for(int i=0;i<hl;i++)
		{
			for(int j=0;j<hl;j++) rec[i][j]=s.nextInt();
		}
		int ans[][]=recpow(rec,ci);
		for(int i=0;i<hl;i++)
		{
			for(int j=0;j<hl;j++)
			{
				System.out.print(ans[i][j]+" ");
			}
			System.out.println();
		}
	}

	private static int[][] recpow(int[][] rec, int ci) {
		// TODO Auto-generated method stub
		int len=rec.length;
		int ans[][]=new int[len][len];
		//初始为 1 0 0
//				0 1 0
//				 0 0 1
		for(int i=0;i<len;i++)
			ans[i][i]=1;
		while(ci!=0)
		{
			if((ci&1)==1)
				ans=mul(ans,rec);
			rec=mul(rec,rec);
			ci>>=1;
		}
		return ans;
	}

	private static int[][] mul(int[][] ans, int[][] rec) {
		// TODO Auto-generated method stub
		//这里只考虑ans和rec两矩阵 长宽相同
		int len=ans.length;
		int Ans[][]=new int[len][len];
		for(int i=0;i<len;i++)
		{
			for(int j=0;j<len;j++)
			{
				for(int k=0;k<len;k++)
				{
					Ans[i][j]+=ans[i][k]*rec[k][j];
				}
			}
		}
		return Ans;
	}
}

11 ,欧拉定理:

欧拉定理中包含一个欧拉函数:
n的欧拉函数是:1-n中与n互质的个数
在这里插入图片描述

12:三角形公式:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

13,概率问题:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值