蓝桥杯做题总结(1)-数学方法

写在前面 :一些经常忘记的知识

sort(begin,end)  
一般是升序sort(a,a+n) a是数组名,n是数组长度
降序的时候用#include<functional>
sort(a,a+n,greater<int>());

强制转换数据类型是 (double) x  !!!!
也可以x * 1.0

普通输入挂怎么写
#include<cstdio>;
int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=x*10+c-'0'; 
		c=getchar();
	}
	return x*f;
} 
int main(){
	int n=read();
	printf("%d",n);
	return 0;
}
int n;
while(scanf("%d",&n)!=EOF);
while(cin>>n);这个对于未指定个数的输入有用

printf常考
 1. %3d  表示输出3位整型数, 不够3位右对齐。 %03d  表示输出3位整型数, 不够3位前面用0补齐。
 2. %9.2f 表示输出场宽为9的浮点数, 其中小数位为2, 整数位为6double类型的lf也一样
 3.  %-7d  表示输出7位整数左对齐  这个-就是左对齐
 4. %d int  %ld long  %lld long long

#include<bitset>
cout<<(bitset<5>)n;   将n转换成长度为5的二进制串

#include<string>中string常用函数
string s='i can see you.';
char s1[10];
 1. s可以用下标的方式输出 下标从0开始,s[0]=i;
 2. 输入字符串有空格就用getline(cin,s),另外用scanf("%[^\n}",s1)
 3. s.size()和s.length()可以求字符串长度
 4. s.substr(begin,len)可以取出字串从begin位置开始取出长度为len的字串

#include<vector>  动态数组
vector <int> v;     创建一个vector v
int a[10];  vector <int> v2(a,a+10);
vector<int>v3(10,1); vector中有10个类型为int1
v.push_back(10);10加入v的最后面
v.pop_back();        从后取数
int x=v[0];          v可以用下标的方式取数
vector查找用find函数需要加上头文件
#include<algorithm>
vector <int>::iterator it=find(v.begin(),v.end(),x)
if(it==v.end())//没找到

海伦公式
int a,b,c;
cin>>a>>b>>c;
int p=(a+b+c)/2;
int s=sqrt(p*(p-a)*(p-b)*(p-c));

卡特兰数

可以看https://www.bilibili.com/video/BV1nE411A7ST
up讲的很清楚

//卡特兰数 n个节点可以构成几种二叉树 
//f(n)=f(0)*f(n-1)+f(1)*f(n-2)+...+f(n-1)*f(0)
#include<iostream>
using namespace std;
long long f[20]={1};//f(0)=1;0个节点可以构成空树 
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=0;j<i;j++){
			f[i]+=f[j]*f[i-1-j];
		}
	}
	cout<<f[n];
	return 0;
} 

STL二分查找

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
/*
upper_bound返回第一个大于所查找值的指针--相当于右侧二分+1 
要转化成下标就是 r-a
lower _bound返回第一个大于等于所查找值的指针 相当于左侧二分
如果找不到的话,则两个函数返回值一样
找得到的话,值不同
x  1 2 4 8 
u  1 4 7 8
l  0 1 7 8
*/ 
int main(){
	int a[]={1,2,2,2,3,3,3,7};
	int *r1=upper_bound(a,a+8,1);
	int *l1=lower_bound(a,a+8,1);
	cout<<r1-a<<' '<<l1-a<<endl;
	int *r2=upper_bound(a,a+8,2);
	int *l2=lower_bound(a,a+8,2);
	cout<<r2-a<<' '<<l2-a<<endl;
	int *r3=upper_bound(a,a+8,4);
	int *l3=lower_bound(a,a+8,4);
	cout<<r3-a<<' '<<l3-a<<endl;
	int *r4=upper_bound(a,a+8,8);
	int *l4=lower_bound(a,a+8,8);
	cout<<r4-a<<' '<<l4-a<<endl;
	return 0;
}

在这里插入图片描述

二分查找

有三种二分(经典二分,左侧二分-查找第一个出现的数,右侧二分查找最后一个出现的数)

#include<cstdio>
#include<iostream>
#include<algorithm>
int a[1000]; 
using namespace std;
int check_left(int x,int low,int high){
	int l=low,r=high;
	while(l<=r){
		int mid=l+(r-l)/2;
		if(x==a[mid])r=mid-1;
		else if(x<a[mid])r=mid-1;
		else l=mid+1;
	}
	if(l>high||a[l]!=x) return -1;
	return l;
}
int check_right(int x,int low,int high){
	int l=low,r=high;
	while(l<=r){
		int mid=l+(r-l)/2;
		if(x>=a[mid])l=mid+1;
		else if(x<a[mid])r=mid-1;
	}
	if(r<low||a[r]!=x) return -1;
	return r;
} 
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>a[i];
	sort(a,a+n);
	int x=2;
	cout<<check_right(x,0,n-1);
	return 0;
}
下面的写的有问题
//经典二分
while(low<=high){//注意!!!
	mid=low+(high-low);/2//防止溢出
	if(a[mid]==x)return mid;//重点
	else if(a[mid]>x) high=mid-1;
	else low=mid+1;
}
return -1;
//左侧二分
while(low<=high){
	mid=low+(high-low);/2//防止溢出
	if(a[mid]==x)return high=mid-1;//应该向左侧靠,缩小右边边界
	else if(a[mid]>x) high=mid-1;
	else low=mid+1;
}
if(left>n||a[left]!=x) return -1;//查找不到返回-1
return low;//返回左边的下标

欧拉函数

//欧拉函数 判断一个数与(1,n)之间的整数互质的个数 
//公式法 
#include<iostream> 
using namespace std;
int oula(int n){
	int ans=n;
	//这里是质因式分解 
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			//只要余数得0,则一定是质因数,套用公式
			ans=ans/i*(i-1);	 
			while(n%i==0){
				n/=i;
			}
		} 
	}
	if(n>1)ans=ans/n*(n-1);
	return ans;
} 
int main(){
	int n;
	cin>>n;
	cout<<oula(n);
	return 0;
}

欧拉筛

//欧拉筛
#include<iostream>
using namespace std;
const int N=10000;
//phi[i]=x表示在1-i中与i互质的个数有x个
//prime表示质数个数 
int phi[N],prime[N];
//标记i是否为质数,是合数就置0 
bool flag[N];
void EulerFilter(int n){
	phi[1]=1;
	int count=0;
	for(int i=2;i<=n;i++){
		if(flag[i]==0){
			prime[++count]=i;
			//如果i是质数,利用欧拉函数的性质
			//质数的欧拉函数值等于质数-1 
			phi[i]=i-1; 
		}
		//欧拉筛是i的所有质数倍
		//素数筛是质数的所有i倍 
		for(int j=1;j<=count&&i*prime[j]<=n;j++){
			flag[i*prime[j]]=1;
			if(i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];
			}
			else{
				phi[i*prime[j]]=phi[i]*(prime[j]-1);
			}
		} 
	}
}
int main(){
	int n;
	cin>>n;
	EulerFilter(n);
	for(int i=1;i<=n;i++)
		cout<<phi[i]<<' ';
	return 0;
}

素数筛

//素数筛
#include<iostream>
using namespace std;
const int N=10000;
bool flag[N];
int main(){
	int n;
	cin>>n;
	flag[1]=1;
	int count=0;
	for(int i=2;i<=n;i++){
		if(flag[i]==0){
			for(int j=2;i*j<=n;j++){
				flag[i*j]=1;
			}
			count++;
		}
	}
	cout<<count;
	return 0;
} 

质因式分解

//这种是容易理解的方法
//分解质因式,分解从1-n的质因式
//表达形式为8=2*2*2 
#include<iostream>
using namespace std;
int IsPrime(int x){
	if(x==1)return 0;
	for(int i=2;i*i<=x;i++){
		if(x%i==0)return 0;
	}
	return 1;
}
int main(){
	int n,i,j,temp;
	cin>>n;
	for(i=1;i<=n;i++){
		temp=i;
		if(IsPrime(temp)||temp==1){cout<<temp<<"="<<temp<<endl;continue;} 
		cout<<temp<<"=";
		for(j=2;j<temp;j++){//注意这里式<temp temp的质因子只能
		//是在2-temp-1之间,而且temp的值在变 
			if(IsPrime(j)){
				while(temp%j==0){
					temp/=j;
					cout<<j<<"*";
					//如果temp被除的只剩下一个质数 
					if(IsPrime(temp)){
						cout<<temp;
						goto end;
					}	
				} 	
			}
		}
		end:cout<<endl;
	}
	return 0;
}
//分解质因数 输出N的质因数的个数。
#include<iostream>
using namespace std;
int main(){
	int n;
	cin>>n;
	int count=0;
	//不用判断是否是质数
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			while(n%i==0){
				n/=i;
				count++;
			}
		}
	} 
	if(n>1)count++;
	cout<<count;
	return 0;
} 

高精度

//核心
	for(i=1;i<lc;i++)
	{
		c[i]+=a[i]+b[i];
		c[i+1]=c[i]/10;
		c[i]%=10;
	}

for(i=1;i<=la;i++)
	{
		for(j=1;j<=lb;j++)
		{
			c[i+j-1]+=a[i]*b[j];
			c[i+j]+=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
	}

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

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<stdio.h>
#include<string.h>
using namespace std;
void High_precisionaddition()
{
	string s1,s2;
	cin>>s1>>s2;
	int a[100]={0},b[100]={0},c[1000]={0},i,la,lb,lc;
	la=s1.size();
	lb=s2.size();
	//lc=la+lb;和乘法搞混了 
	lc=max(la,lb)+1;//注意这个lc不一定是最后和的长度,还要判断前导零 
	for(i=la-1;i>=0;i--)
		a[la-i]=s1[i]-'0';
	for(i=lb-1;i>=0;i--)
		b[lb-i]=s2[i]-'0';//注意这里是从1开始存储 
	for(i=1;i<lc;i++)
	{
		c[i]+=a[i]+b[i];
		c[i+1]=c[i]/10;
		c[i]%=10;
	}
	//高位低位一直没搞清楚
	//一开始string把高位存在0处,用一个数组把地位存在1处好进行计算
	//输出的时候应该先输出高位,但是要先判断是否有前导零,就是c[lc]的地方是否为0
	//还要注意 0+0的情况 
	for(i=1;i<=lc;i++)
	{
		if(c[i]!=0)break;
		if(i==lc)
		{
			cout<<0;
			return;
		}
	}
	for(int i=lc;i>=1;i--)
	{
		if(c[i]==0&&i==lc)continue;
		cout<<c[i];
	}
}
void High_precisionmultiplication()
{
	string s1,s2;
	cin>>s1>>s2;
	int a[100]={0},b[100]={0},i,j,la,lb,lc;
	//对于一些要求位数很大的题,可以用malloc分配内存
	int* const c=(int*)malloc(sizeof(int)*100000);
	memset(c,0,sizeof(c)*100000);
	la=s1.size();
	lb=s2.size();
	lc=la+lb;
	for(i=la-1;i>=0;i--)
		a[la-i]=s1[i]-'0';
	for(i=lb-1;i>=0;i--)
		b[lb-i]=s2[i]-'0';//注意这里是从1开始存储 
	//这里是个二重循环
	for(i=1;i<=la;i++)
	{
		for(j=1;j<=lb;j++)
		{
			c[i+j-1]+=a[i]*b[j];
			c[i+j]+=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
	} 
	for(i=lc;i>0;i--)
	{
		if(c[i]!=0)break;
	}
	for(j=i;j>0;j--)
		cout<<c[j];
}
int main()
{
	//High_precisionaddition();
	High_precisionmultiplication();
	return 0;
}

gcd和lcm

编写一函数gcd,求两个正整数的最大公约数和最小公倍数
总结:
用辗转相除(欧几里得)来求gcd,lcm就是两数乘积除以gcd得出的商
(辗转相除就是我们初高中学的,但是那时候我只知道该怎么做,不懂为啥那么做,下面是我结合一些网上的求证写出的证明思路)
(枚举就不说了)

在这里插入图片描述

多数就是先求出两个数的gcd,再用gcd与另一个数求出gcd
	int gcd(int[] a,int n) {//a保存了数,n是数组长度
		int g = a[0];
		for(int i=1;i<n;i++)
			g = gcd(g,a[i]);
		
		return g;
	}
	
	 int lcm(int[] a,int n) {
		int l = a[0];
		for(int i=1;i<n;i++)
			l = lcm(l,a[i]);
		
		return l;
	}
int gcd(int a,int b)//注意a>b
{
	int r=a%b;
	if(!r)return b;
	gcd(b,r);
}
int lcm(int a,int b)
{
	return a*b/gcd(a,b);
}

1)Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson。现 在,刚刚放学回家的Hankson 正在思考一个有趣的问题。 今天在课堂上,老师讲解了如何求两个正整数c1 和c2 的最大公约数和最小公倍数。现 在Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公 倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整 数x 满足: 1. x 和a0 的最大公约数是a1; 2. x 和b0 的最小公倍数是b1。 Hankson 的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的 x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x 的个数。请你帮 助他编程求解这个问题。
【输入形式】
  输入第一行为一个正整数n,表示有n 组输入数据。

接下来的n 行每 行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入 数据保证a0 能被a1 整除,b1 能被b0 整除。

数据规模和约定
  对于 50%的数据,保证有1≤a0,a1,b0,b1≤10000 且n≤100。
  对于 100%的数据,保证有1≤a0,a1,b0,b1≤2,000,000,000 且n≤2000。

【输出形式】
  输出共n 行。每组输入数据的输出结果占一行,为一个整数。
  对于每组数据:若不存在这样的 x,请输出0; 若存在这样的 x,请输出满足条件的x 的个数;
【样例输入】

2
41 1 96 288
95 1 37 1776

【样例输出】

6
2

【提示】
样例说明
  第一组输入数据,x 可以是9、18、36、72、144、288,共有6 个。
  第二组输入数据,x 可以是48、1776,共有2 个。
(实在数学不好,直接公式暴力只能得一半分,等我研究清楚了再写)

#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
int gcd(int a,int b)//注意a>b
{
	int t=a;
	if(t<b)
	{
		t=b;
		b=a;
		a=t;
	}
	int r=a%b;
	if(!r)return b;
	gcd(b,r);
}
int lcm(int a,int b)
{
	return a*b/gcd(a,b);
}
int main()
{
	int n,a0,a1,b0,b1,x,c=0;
	cin>>n;
	while(n--)
	{
		c=0;
		//cout<<'dhf';
		cin>>a0>>a1>>b0>>b1;
		for(x=a1;x<=b1;x+=a1)//a1整除x
		{
			if(gcd(x,a0)==a1&&lcm(x,b0)==b1)
				c++;
		}
		cout<<c<<endl; 
	}
	
	return 0;
}

快速幂

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<stdio.h>
#include<string.h>
using namespace std;
int qpow()
{
	int a,m;//a^m
	cin>>a>>m;
	int prod=1;//连乘器 
	while(m>0)
	{
		if(m&1)
			prod=prod*a;
		a*=a;
		m>>=1;
	}
	cout<<prod;
	return prod;
}
int main()
{
	qpow();
	return 0;
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值