二分
完美数列
关于lower_bound和upper_bound的第二种用法
int t=lower_bound(a,a+n,k)-a 返回第一个大于等于k的下标,如果k比数组里面所有的数都大,就返回a+n,如果k比所有数都小,返回第一个元素下标
int t=upper_bound(a,a+n,k)-a 返回第一个大于k的下标,如果k比数组所有元素都大,就返回a+n,如果k比所有数都小,返回第一个元素下标
(摘自https://www.cnblogs.com/caijiaming/p/9316716.html)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=100010;
int n,p,a[maxn];
//求递增序列中第一个大于x的元素的位置
int upper_bound(int A[],int left,int right,int x)
{
int mid;
while(left<right)//注意这里没有等号
{
mid=left+(right-left)/2;
if(A[mid]>x)
{
right=mid;
}
else
{
left=mid+1;
}
}
return left;
}
int main()
{
scanf("%d%d",&n,&p);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
int ans=1;
for(int i=0;i<n;i++)
{
int j= upper_bound(a+i+1,a+n,(long long)a[i]*p)-a;
ans=max(ans,j-i);
}
printf("%d\n",ans);
return 0;
}
给出一个数字序列和一个数S,在数字序列中求出所有和值为S的连续子序列。若没有这样的序列,求出和值恰好大于S的子序列(即在所有和值大于S的子序列中和值最接近S)。下标从1开始。
#include <iostream>
#include <cstdio>
const int N=100010;
using namespace std;
int sum[N];
int n,S,nearS=100000010;
int upper_bound(int L,int R,int x)
{
int left=L,right=R,mid;
while(left<right)
{
mid=(left+right)/2;
if(sum[mid]>x)
{
right=mid;
}
else
{
left=mid+1;
}
}
return left;
}
int main()
{
scanf("%d%d",&n,&S);
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&sum[i]);
sum[i]+=sum[i-1];
}
for(int i=1;i<=n;i++)
{
int j=upper_bound(i,n+1,sum[i-1]+S);
if(sum[j-1]-sum[i-1]==S)
{
nearS=S;
break;
}
else if(j<=n&&sum[j]-sum[i-1]<nearS)
{
nearS=sum[j]-sum[i-1];
}
}
for(int i=1;i<=n;i++)
{
int j=upper_bound(i,n+1,sum[i-1]+nearS);
if(sum[j-1]-sum[i-1]==nearS)
{
printf("%d-%d\n",i,j-1);
}
}
return 0;
}
two points
完美数列(同二分法题目,利用two points解)
#include <cstdio>
#include <algorithm>
using namespace std;
int n,p;
int a[100010]={0};
int count=1;
int main()
{
scanf("%d%d",&n,&p);
int i=0;
while(i<n)
{
while(j<n&&a[j]<=a[i]*p)
{
count=max(count,j-i+1);
j++;
}
i++;
}
printf("%d\n",count);
return 0;
}