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位。