杭电基础算法学习笔记 第1讲 基础数学

2022/1/12

例1:辗转相除法(欧几里得算法)

给定两个整数,计算这两个数的最小公倍数。

input:

10 14

4 6

output:

70

12

几种想法:

1. 1~m*n逐个枚举

2. 从大数m开始,枚举2m,3m,4m,.....,n*m一定有

3. LCM(A,B)=A*B/GCD(A,B)        注意A*B有时会爆int,需要longlong int或者先除

最大公约数 Greatest Common Divisor(GCD)

最小公倍数 Lowest Common Multiple(LCM)

//欧几里得算法(辗转相除法计算最大公约数) 
#include <stdio.h> 
int gcd(int da, int xiao)/*最开始传如果是先小后大,那循环一次
						大小就调过来了,不会出现异常*/ 
{	int temp;
	while (xiao!=0)
	{
		temp=da%xiao;	//中间临时变量的操作在swap里面也有 
		da=xiao;
		xiao=temp;
	}
	return (da);
}

int main()
{
	int a,b,lcm,gcd1;	//gcd最大公约数 lcm最小公倍数 
	scanf("%d %d", &a,&b);
	gcd1 = gcd(a,b);
	lcm=a/gcd1*b;		/*int最大是21亿左右,要注意超没超范围。
						此外,结果不超范围也可能中间计算过程中超范围
						能先除先减的运算一定先做*/ 
	printf("%d\n",lcm);	
}

感觉自己目前的问题不是数学基础不行,小奥竞赛都学过,都很简单,但是转换成了代码要么就是长度复杂好几倍,要么就是运行出错,要么就是变量太多冗余。

例2:找规律

给定一个正整数N,请计算N个N相乘的结果的个位数是多少(1<=N<=1,000,000,000)

Sample Input

3

Sample Output

7

思路:

1. 先算个位

2. 个位数乘积有循环(1-1,2-4,3-4,5-1,6-1,7-4,8-4,9-2)

循环的最小公倍数是4,只有乘的次数去mod4就可以了。

3. 为什么一定有循环?抽屉原理

例3:找规律

给定斐波那契数列的前两项,判断F(n)能否被3整除(n<1,000,000)

原理:抽屉原理。相邻两项mod3只有九种组合,最多9个一个循环节

推广:任意n阶递推数列,判断F(m)能否被p整除,循环节不超过p^n

例4:快速幂运算

求A^B的最后三位数表示的整数(1<=A,B<=10,000)

10,000还是很简单的,暴力就可以(最暴力的暴力,改进的暴力)

Sample Input

2 3

12 6

Sample Output

8

984

一种新的方法:快速幂运算(二分加速) 

#include <stdio.h>
/*快速幂运算的递归实现*/
int power (int a, int n)		//power幂;乘方 
{
	int ans;                    //ans是answer的缩写
	if (n==0) ans=1;			//结束条件 :递归先写结束条件 
	else
	{
		ans=power (a*a, n/2);	//递归调用 :每次调用底数平方幂指数减半 
		if(n%2==1) ans*=a;		//n为奇数 
	} 
	return ans;
} 

int main()
{
	int a, n;
	scanf("%d %d", &a, &n);
	printf("%d", power (a, n));
	return 0;
}

/*快速幂运算的非递归实现(循环)*/
int power2(int a, int n)
{	int ans=1;
	while(n)
	{	if(n%2) ans=ans*a;	//奇数情况 
		a=a*a;				//底数平方 
		n=n/2;				//指数减半 
	}
	return ans;
} 

实际上使用的时候一般是去模,比如看后三位

例5:二分查找法

给出若干个有序的整数,请查找某个元素是否存在。

比如,2,3,4,5,6,8,12,20,32,45,65,74,86,95,100

循环实现

/*二分查找——循环实现*/
int BiSearch(int a[],int n,int x)	//传入的参数:n个数的数值,n,要查的数x 
{
	int left = 0, right=n-1;
	while(left<=right)				//注意=不能少 
	{
		int middle=(left+right)/2;	//整数除法 
		
		if(a[middle]==x)			//找到的情况 
			return middle;
		if (x>a[middle])			//如果比中值大 
			left=middle+1;
		else						//如果比中值小 
			right=middle-1;
	}
	return -1;						//没查到的情况返回-1 
} 

递归实现

int BiSearch(int a[],int x,int left,int right)
{
	if(left>right)					//注意不能有等号 
		return -1;
	else
	{
		int mid=(left+right)/2;
		if(a[mid]==x)
			return mid;
		else if(x>a[mid])
			return BiSearch(a,x,mid+1,right);
		else if(x<a[mid])
			return BiSearch(a,x,left,mid-1);
	}
}

例6

给出方程:8*x^4+7*x^3+2*x^2+3*x+6=y,其中y满足(fabs(y)<=1e10)

请写出x在区间[0,100]的解,精确到小数点后4位。

#include <bits/stdc++.h>
using namespace std;
double Y;
double Left, Right, mid;
double f(double x)
{
	return 8*pow(x,4.0)+7*pow(x,3.0)+2*pow(x,2.0)+3*x+6;
} 

int main()
{
	int t;
	scanf("%d", &t);	
	while(t--)
	{
		scanf("%lf", &Y);
		if (f(0)<=Y&&Y<=f(100)){
			Left=0.0; Right=100.0;
			while(Right-Left>1e-6) {
				mid = (Left+Right)/2;
				double ans = f(mid);
				if (ans>Y)
					Right = mid -1e-7;
				else
					Left = mid + 1e-7;
			}
			printf("%.4f\n",(Left+Right)/2);
		}
		else
			printf("No solution\n");
	}
}

例7

给出函数F(x) = 6*x^7+8*x^6+7*x^3+5*x^2-y*x,其中0<y<1e10

请输出x在区间[0,100]时函数F(x)的最小值,结果精确到小数点后4位。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值