1.P8682 [蓝桥杯 2019 省 B] 等差数列
首先,将N个整数用sort由小到大排序。
然后,希望找到最大的d,一开始用的是双层循环,直接爆了TLE,后来改用函数gcd求任意两项之间的最大公约数(更相减损法)。
最后,用an=a1+(n-1)*d求项数。
#include <bits/stdc++.h>
using namespace std;
int gcd(int x,int y)
{
while(x!=y){
if(x>y)
x = x-y;
else
y = y-x;
}
return x;
}
int main()
{
int n;
cin>>n;
int a[n];
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
if(a[0]==a[n-1]){
cout<<n;
return 0;
}
int d = a[1]-a[0];
for(int i=1;i<n;i++)
d = gcd(d,a[i]-a[i-1]);//如果初始i=0,那么会出现a[0]-a[-1]的情况,导致数组越界
//cout<<d;
int ans = (a[n-1]-a[0])/d+1;
cout<<ans;
return 0;
}
另:(1) 求等差数列还可以用辗转相除法加递归。
int gcd(int x, int y)
{
if (y == 0)
return x;
return gcd(y, x % y);
}
(2) if(d==0),即每一项的值都相等,则项数直接为n。(不提前说明#1会报RE)
2.P1226 【模板】快速幂
快速幂递归实现
int ksm(int a,int n)
{
int ans;
if(n==0) ans=1;
else{
ans = ksm(a*a,n/2);
if(n%2==1) ans *= a;
}
returm ans;
}
显而易见,本题使用快速幂(喜欢循环)。
因为数据的范围能达到二的31次方,所以用long long搭配取模。
#include <iostream>
using namespace std;
long long b,p,k;
//循环快速幂
long long ksm(long long a,long long n){
long long ans=1;
while(n){
if(n%2==1) ans = ans*a%k;//如果n为单数,乘到ans里面去,然后取模
a =a*a%k;
n /= 2;
}
return ans;
}
int main()
{
cin>>b>>p>>k;
long long res = ksm(b,p);
res %= k;
printf("%lld^%lld mod %lld=%lld", b, p, k, res);
return 0;
}
3.P2249 【深基13.例1】查找
提示单调不减数列,明显可以使用二分查找降低时间复杂度,所以果断二分。
注意:因为这里的find函数中while循环结束条件是left==right,所以一旦找到与目标数字相同的数会自动覆盖掉原来的mid,使得最终结果一定第一个编号。
#include <bits/stdc++.h>
using namespace std;
int a[1000010];//a[]表示n个整数
int n,m,k;
int find(int x)
{
int left=1,right=n,mid;
while(left<right){
mid=(left+right)/2;
if(a[mid]>=x)
right = mid;
else
left = mid+1;
}
if(a[left]==x)
return left;
else
return -1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
while(m--){
cin>>k;
int ans = find(k);
cout<<ans<<" ";
}
return 0;
}
4.P1824 进击的奶牛
二分:最大值最小化或者最小值最大化
翻译题意:有n个坐标,存在x满足m(m<n)个坐标之间的距离最大,求x。
累了,直接上注释。
#include <bits/stdc++.h>
using namespace std;
int a[100010];
int n,c,ans;
//判断x是否符合题意
bool check(int x)
{
int now=0,num=1;//now:第一头奶牛肯定在第一个隔间,num:安排的奶牛数量
for(int i=1;i<n;i++){
if(a[i]-a[now]>=x){
now=i;
num++;
}
}
return num>=c;//能安排的数量大于c,x成立,返回1;否则返回0
}
//二分找答案
void merge(int l,int r)
{
if(l>r) return;
int mid = (l+r)/2;//还可以mid=l+(r-l)/2,防溢出
if(check(mid)){//如果mid满足,记录下来,然后在左边接着找
merge(mid+1,r);
if(ans>mid) ans = ans;
else ans = mid;
}
else//反之,在右边找
merge(l,mid-1);
}
int main()
{
cin>>n>>c;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
merge(0,a[n-1]-a[0]);
cout<<ans;
return 0;
}