P8682 [蓝桥杯 2019 省 B] 等差数列
找到最短的等差数列
即 1) 找到公差d
2)找到最大和最小项
公差d的找法就是找出满足输入数的最大的公差
即找到相差最小的两个数的差 作为公差d
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
int a[1000000];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
int d=a[1]-a[0];
for(int i=0;i<n;i++)
{
if(a[i+1]-a[i]<d&&a[i+1]>=a[i]){d=a[i+1]-a[i];
}
}
if(d==0) cout<<n;
else cout<<(a[n-1]-a[0])/d+1;
return 0;
}
P1226 【模板】快速幂
本题主要难点出在数据比较大
则考虑使用pow(a,n)=pow(a*a,n/2)的方式减少时间复杂度
由于数据较大 所以每次计算完取模计算 保证数据不超
#include<bits/stdc++.h>
using namespace std;
long long f(long long a,long long b,long long p)
{
long long ans=1;
while(b>0)
{
if( b%2!=0){
ans=ans*a;
ans%=p;
}
a=a*a;
a=a%p;
b=b/2;
}
return ans%p;
}
int main()
{
long long a,b,p;
cin>>a>>b>>p;
long long k=f(a,b,p)+p;
cout<<a<<"^"<<b<<" mod "<<p<<"="<<k%p;
}
P2249 【深基13.例1】查找
本题难点也是数据量大
为了减少时间复杂度 使用二分查找
时间复杂度为o(nlogm)
考虑使用lower_bound二分查找出第一个大于等于x的数据的地址
(upper_bound是找出第一个大于的数据的地址)
由于是地址 所以需要-a
ps:若需要找到一个小于等于的为lower_bound(begin,end,x,greater<type>())
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int a[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
while(m)
{
int x;
cin>>x;
int ans=lower_bound(a,a+n,x)-a;
if(x!=a[ans]) printf("-1 ");
else printf("%d ",ans+1);
m--;
}
return 0;
}
P1223 排队接水
思路比较自然 找出最小的先往前排 再计算总和
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
int a[n],t[n],s[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
t[i]=a[i];
}
int mx=0;
int m=n;
int j=0;
while(m)
{ mx=10000000;
for(int i=0;i<n;i++)
{
if(t[i]<mx) {s[j]=i;mx=t[i];
}
}
t[s[j]]=10000001;
cout<<s[j]+1<<" ";
if(m==1) cout<<endl;
m--;
j++;
}
double sum=0;
for(int i=0;i<n;i++)
{
sum+=a[s[i]]*(n-1-i);
}
sum=1.0*sum/n;
cout<<fixed<<setprecision(2)<<sum;
return 0;
}
P1803 凌乱的yyy / 线段覆盖
贪心算法
排序以后贪心 找到最早结束的一个时间
注意用sort结构体的排序 从小到大排序
#include<bits/stdc++.h>
using namespace std;
int last=0;
struct oi
{
int a,b;
}arr[10000000];
bool cmp(oi x,oi y)
{
return x.b<y.b;
}
int main()
{
int n;
cin>>n;
int ans=0;
for(int i=0;i<n;i++)
{
cin>>arr[i].a>>arr[i].b;
}
sort(arr,arr+n,cmp);
for(int i=0;i<n;i++)
{
if(arr[i].a<last) continue;
ans++;
last=arr[i].b;
}
cout<<ans;
}
P1031 [NOIP2002 提高组] 均分纸牌
只需要从第一项开始看
让第二项取给或者收 第一项少的或多的牌
如果正好则不计入次数
#include<bits/stdc++.h>
using namespace std;
bool cmp(int a, int b)
{
return a>b;
}
int main()
{
int n;
cin>>n;
int a[n];
int total=0;
int k;
for(int i=0;i<n;i++)
{
cin>>a[i];
total+=a[i];
}
k=total/n;
int ans=0;
for(int i=0;i<n;i++)
{
if(a[i]==k) continue;
else if(a[i]!=k) {
a[i+1]+=a[i]-k;
ans++;
}
}
cout<<ans;
return 0;
}
P1824 进击的奶牛
最大值的最小和最小值的最大考虑使用二分法
难点为check(int x)函数
我的思路是先排序,从最小的数开始找 找到第一个满足距离大于x的另一个牛栏
计算能找的数量总和是否满足
再使用二分法从0 到a[n-1]中找到满足的最大的x为答案
#include<bits/stdc++.h>
using namespace std;
int n,c,a[10000000];
bool check(int x)
{
int k=a[0];
int ans=1;
for(int i=1;i<n;i++)
{
if(a[i]-k>=x) {
k=a[i];
ans++;
}
}
if(ans>=c) {
return true;
}
else return false;
}
int main()
{
cin>>n>>c;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
int left=0,right=a[n-1];
int mid=(left+right)/2;
while(left<right)
{
mid=(left+right)/2;
if(check(mid)!=0){left=mid+1;
}
else right=mid-1;
}
if(check(right))cout<<right;
else cout<<right-1;
}
P1007 独木桥
本题难点在于 人转来转去
实际上 人转来转去并不影响总时间 即可以看作两个人擦肩而过
#include<bits/stdc++.h>
using namespace std;
int main()
{
int l,n;
cin>>l>>n;
int a[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int s[n],k[n];
for(int i=0;i<n;i++)
{
s[i]=max(a[i]-0,l-a[i]+1);
k[i]=min(a[i],l-a[i]+1);
}
int mx=0,minn=0;
for(int i=0;i<n;i++)
{
if(s[i]>mx){mx=s[i];
}
if(k[i]>minn) minn=k[i];
}
cout<<minn<<" "<<mx;
}