描述
给定N个数字,X1,X2,……XN,让我们计算每一对数的差值:|Xi-Xj| (1 ≤ i < j ≤ N),可以获得C(N,2)个数的中位数(即N*(N-1)/2个)
输入格式
在每个测试用例中,N将在第一行给出。然后Ñ编号给予,表示X 1,X 2,…,X Ñ,( Xi ≤ 1,000,000,000 , 3 ≤ N ≤ 1,00,000 )
输出格式
在单独的行中输出中值
样例输入
4
1 3 2 4
3
1 10 2
样例输出
1
8
题意
N个数两两做差会得到C(N,2)个差值,求这些差值的中位数
思路
第一眼看到的想法就是把所有的差值求出,再找中位数,但一看数据N最大可以去到100000两两求差值N2必超时。中位数前后的前后的元素个数要么一样多(N为奇数),要么差一个(N为偶数),于是我们可以对这个中位数的值进行二分,满足条件的就是这组数据的中位数,那么问题来了怎么求差值,都求出来肯定不行,会超时,那我们就一边求一边判断(记得这个时候先把数组排个序,差值一旦大于二分出来的mid,就不用再求后面的了,越来越大了呀)把小于mid的进行计数,最后判断这个mid符不符合中位数的条件,然后就是二分的老套路了
AC代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int a[100010];
int n,ans;
int judge(int mid)
{
int cnt=0,t=0;
for(int i=0;i<n;i++)
{
while(t<n&&a[t]-a[i]<mid)//求差值判断是不是在mid的前面
t++;
cnt+=t-i-1;
}
if(cnt>=ans)//将计得的数与中位数的条件比较看能否成为中位数
return 1;
else
return 0;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int m=n*(n-1)/2;
//两种情况下的中位数位置
if(m%2==0)
ans=m/2;
else
ans=(m+1)/2;
sort(a,a+n);//排序,为judge当中的while循环准备的,能够减少循环次数
int left=0,mid,right=a[n-1]-a[0],res;
while(right-left>=0)
{
mid=(right+left)/2;
if(judge(mid))
right=mid-1;
else
left=mid+1;
}
printf("%d\n",right);
}
}
描述
在我的生日派对上有N个饼,每个饼的大小不同,有许多朋友来参加我的生日派对,他们每一个人都得到了一块饼,如果其中有一个的饼比另一个人的大,他们就会抱怨,所以所有的饼应该分成相同的大小,当然了,我自己也要一块饼,而且那块也应该是同样的大小,我们所有人可能得到的最大尺寸的饼是多少?我做的饼都是圆柱形的,高度都是1,但是半径可以不一样。
输入格式
一行为正整数:测试用例的组数
然后对于每个测试用例:一行带有两个整数N,F带有1<=N,F<=10000表示饼的数目和好友的数目。
一行N个整数ri,1<=ri<=10000:饼的半径。
输出格式
对于每个测试用例,输出一行具有最大可能的数值,这样我和我的朋友都可以得到一块大小为V的饼。答案应该以浮点数给出,绝对误差最多为10^(-7)保留6位小数。
样例输入
3
3 3
4 3 3
1 24
5
10 5
1 4 2 3 4 5 6 5 4 2
样例输出
25.132741
3.141593
50.265482
题意
N+1个人分饼,饼不止一个,每个人的饼要一样大,求每个人分的饼最大有多大
思路
这个类似之前写的那个切绳子,二分过程一样,两道题都卡了精度,这里是给出了绝对误差的最大值,一开始没能理解这个,哪里会有误差存在呢,其实就是二分越往后分right和left靠的越来越近,这个地方能出现误差,所以我们可以让right和left的差值小于10-7时结束while。还有就是这题精度比较高要六位小数,所以Π的值还是搞精确点用acos(-1)来表示。
AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define PI acos(-1)
using namespace std;
double v[100010];
int N,F;
int cut(double mid)
{
int cnt=0;
for(int i=0;i<N;i++)
{
cnt+=(int)(v[i]/mid);//记得转int
}
if(cnt>=F)
return 1;
else
return 0;
}
int main()
{
int T;
cin>>T;
while(T--)
{
double R,maxn=0;
cin>>N>>F;
F++;//加上自己
for(int i=0;i<N;i++)
{
cin>>R;
v[i]=R*R*PI;
maxn=max(maxn,v[i]);
}
double left=0,mid,right=maxn;
while(right-left>=1e-7)//允许误差范围
{
mid=(right+left)/2.0;
if(cut(mid))
left=mid;
else
right=mid;
}
printf("%.6lf\n",mid);//保留六位小数
}
return 0;
}