本篇博客涉及欧几里得算法、快速幂算法、二分搜索和二分答案。本篇博客用于自己的学习,如有错误,希望各位大佬帮我指出错误(不要喷我),我也会虚心求教,及时改正。(如有雷同,大抵是巧合)
1、
题目:数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中 N 个整数。现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?
思路:用到欧几里得算法 第一步先输入n和n个数并将这n个数储存到数组中,然后用sort函数对它们进行排序,然后分别求出这n个数相邻两数之间的差值,然后使用欧几里得算法求各元素差值的最大公约数(写一个函数) ,因此就能求出等差数列的方差,并且最大数和最小数都已知,即可求出这个等差数列共有几个数
# include <bits/stdc++.h>
using namespace std;
long long gcd(long long a,long long b)
{
if(b==0)
return a;
else
return gcd(b,a%b);
}
int main()
{
long long n,a,x;
scanf("%lld",&n);
long long num[n],dm[n-1];
for(a=0;a<n;a++)
{
scanf("%lld",&num[a]);
}
std::sort(num,num+n); //用sort函数排序
for(int b=0;b<n-1;b++)
{
dm[b]=num[b+1]-num[b]; //求各元素差值
}
// 使用欧几里得算法求各元素差值的最大公约数
long long res = dm[0];
for (int i = 1; i < n-1; i++) {
res = gcd(res, dm[i]);
}
if(res==0)
x=n;
else
x=(num[n-1]-num[0])/res+1;
printf("%d",x);
return 0;
}
2、
题目:给你三个整数 a,b,p,求 a^b mod p
思路:用到快速幂运算(数据过大,求模) 先分别输入三个数,因为a,b过大,直接算会爆,所以先 让a取余,然后判断b是否为奇数,并进行相应的快速幂运算,然后a平方取余(防止数据过大,平方后取余),然后让b除2,循环下去可以算出模(res)
#include <stdio.h>
long long fastpower(long long a, long long b, long long mod) {
long long res = 1;
a%=mod;
while (b!=0) {
if (b & 1) res = (res * a) % mod; // 如果b的二进制最后一位为1(b为奇数),那么累乘到结果中
a = (a * a) % mod;
b >>= 1; // b右移一位 ,除2
}
return res;
}
int main() {
long long a, b, p;
scanf("%lld %lld %lld", &a, &b, &p);
if(b==0)
printf("%lld^%lld mod %lld = %lld\n", a, b, p, 1%p);
else
printf("%lld^%lld mod %lld = %lld\n", a, b, p, fastpower(a, b, p));
return 0;
}
3、用二分搜索
题目:输入 n 个不超过 10^9 的单调不减的(就是后面的数字不小于前面的数字)非负整数 a1,a2,…,an,然后进行 m 次询问。对于每次询问,给出一个整数 q,要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 −1 。
思路:先运用二分搜索找到要求的数(设它为x)(没找到就是-1),然后在上界和mid中间遍历找到第一个x(可能会有重复的数字,因此需要找到第一个数字)然后把第一个x对应的位置存起来,最后输出即可
# include <bits/stdc++.h>
using namespace std;
long long search(long long num[],long long len,long long key) //二分法
{
long long low=0; //定义最小
long long high=len-1; //定义最大
long long mid; //定义中间
while(low<=high) //二分法搜索
{
//mid=(low+high)/2;//可能会溢出
mid=low+(high-low)/2; //重点重点重点 找中间值
if(key==num[mid]) //判断mid与key是否相等
{for(long long a=low;a<=high;a++)
{
if(key==num[a])
{
mid=a; //找到第一个‘x’
break;
}
}
return mid+1;
}
else if(key>num[mid]) //如果key>mid 则新区间为[mid+1,high]
low=mid+1;
else //如果key<mid 则新区间为[low,mid-1]
high=mid-1;
}
return -1; //如果数组中无目标值key,则返回 -1 ;
}
int main()
{
long long n,m;
scanf("%lld %lld",&n,&m); //输入n,m
long long num[n],dm[m],cm[m];
for(long long a=0;a<n;a++)
{
scanf("%lld",&num[a]); //输入n个数据
}
for(long long c=0;c<m;c++)
{
scanf("%lld",&cm[c]); //输入m个需要查找的数
}
for(long long b=0;b<m;b++)
{
dm[b]=search(num,n,cm[b]); //找到它们的位置
}
for(long long d=0;d<m;d++)
{
printf("%lld ",dm[d]); //分别输出它们的位置
}
return 0;
}
4、二分答案
题目:Farmer John 建造了一个有 N(2≤N≤10^5) 个隔间的牛棚,这些隔间分布在一条直线上,坐标是 x1,x2,⋯,xN(0≤xi≤10^9)。他的 C(2≤C≤N)头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,Farmer John 想把这些牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好。那么,这个最大的最近距离是多少呢?
思路:先找到上界和下界,然后二分法找到mid,并用judge检测mid是否为可行解,并储存,然后不断二分,找到最大的可行解
# include <bits/stdc++.h>
using namespace std;
long long num[100001],dm[100001];
bool judge (long long x,long long c,long long n) //判断二分法的答案是否符合
{
long long a=1;
long long b=num[1];
for(long long m=2;m<=n;m++) //当间隔为x时,判断能容下几头牛,并比较c和能容下的牛个数
{
if(num[m]-b>=x)
{
b=num[m];
a++;
}
}
if(a>=c)
return true;
else
return false;
}
int main()
{
long long int n,c,b=1,answer=0;
scanf("%lld %lld",&n,&c);
for(long long a=1;a<=n;a++)
{
scanf("%lld",&num[a]); //数组从1开始,便于二分计算
}
sort(num,num+n);
long long left=1,right=num[n],mid;
while(left<=right)
{
mid=(right+left)/2;
if(judge(mid,c,n))
{
answer=mid; //如果为解,则储存该解
left=mid+1;
}
else{
right=mid-1; //二分法找解并找出最优解
}
}
printf("%lld",answer);
return 0;
}