本题让我重视到对lower_bound这个函数不是特别会用。
lower_bound(int * ,int *,int )
第一个参数是数组首地址,由于c++语言的特殊性,传入第一个参数可以是数组首地址+i,表示从数组第i个元素查找(对于下标从1开始的数组)
第二个参数是数组末位+1,这里可以把数组最后一位想象成INF,从头开始,如果发现哪一位大于等于要查找的数字就返回哪一位的地址。
第三个参数是要查找的数字。
然后这道题把所有数字离散化存入一个桶里从小到大排序
然后从第一位到最后一位暴力枚举
1每次都要枚举每一个小于等于这一位上的数字,
2对于枚举的每个数字,每次用lower_bound查找这一位数字后面的所有数字里面第一个大于等于这个数字的数。
3然后把数字乘二,位置移到查找到的位置,
直到位置超出数组总数后更新答案。
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int aa[200010];
int b[200010];
int cnt[200010];
int tot;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
//将a[i]离散化
sort(a+1,a+n+1);
aa[++tot]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]!=a[i-1])
{
aa[++tot]=a[i]; //去重,tot是数组中有几个不同的数字
}
}
for(int i=1;i<=n;i++)
{
b[i]=lower_bound(aa+1,aa+tot+1,a[i])-aa;//lower_bound只对有序数组有效
}
//b[i]里面存了离散化数组
//统计b[i]中有多少每个数字出现的个数
for(int i=1;i<=n;i++)
{
cnt[b[i]]++;//cnt有tot个数字
}
sort(cnt+1,cnt+tot+1);
int res=0;
for(int i=1;i<=tot;i++)
{
int pos=i;
for(int num=1;num<=cnt[pos];num++)
{
int now=0;
int tmp=pos;
int num1=num;
while(tmp<=tot)
{
now+=num1;
tmp=lower_bound(cnt+tmp+1,cnt+tot+1,num1*2)-cnt;
num1*=2;
}
res=max(res,now);
}
}
printf("%d\n",res);
}