题意:
题目输入两组数,找出最合适的三分线设置位置使一队与二队的分差最大(赢得最多或者输得最少)。
题解:
最先想到的一定是枚举三分线位置找到最大分差,但是仔细思考后发现只需要遍历出现过的投球距离就可以,确切的说是只需要遍历a的投篮距离就好。枚举三分线位置,计算得分时采用二分查找定位当前三分线位置,之后计算得分就很简单了。时间复杂度控制在O(nlogn)之内。
关于投篮距离便利的解释:
因为题目要求不超过距离d的都记为两分,超过距离d才记为3分。最开始是想将a,b投篮距离放在一起遍历,但是后来想到其实只需要遍历a的投篮距离,每次遍历的距离设置为a[i]-1,这样可以保证在两个距离区间内无论b怎么取得分始终是最少的,而起a的得分求起来快了很多。最后再在两端取极限值更新一下,时间和空间都比原来的快了一半。
代码实现:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <cstring>
#define MAX 200005
#define INF 0xffffff
using namespace std;
int a[MAX];//team1
int b[MAX];//team2
int n,m;
int score[2];//储存得分
void solve();
bool if_win(int);
int main()
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
//初始化最大
score[0]=0;score[1]=INF;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=0;i<m;i++)
scanf("%d",&b[i]);
//将三个数组排序
sort(a,a+n);
sort(b,b+m);
solve();
return 0;
}
void solve()
{
//遍历
for(int i=0;i<n;i++)
{
//更新
if(i!=0&&a[i]==a[i-1])
continue;
if_win(i);
}
//最后再将左右边界比较一下
a[0]=0;
if_win(0);
a[0]=0xffffff;
if_win(0);
printf("%d:%d\n",score[0],score[1]);
}
bool if_win(int x)
{
int y=a[x]-1;
//s1,s2储存得分,记为long long防止越界
long long s1,s2;
s1=s2=0;
//计算a的得分
if(x!=0)
s1=x*2+(n-x)*3;
else if(x==0&&a[x]==0xffffff)
s1=n*2;
else
s1=n*3;
//用二分计算b的得分
if(b[0]>y)
s2=m*3;
else if(b[m-1]<=y)
s2=m*2;
else
{
double lb=0,ub=2*(m-1);
for(int i=0;i<100;i++)
{
int mid=(int)((lb+ub)/2);
if(b[mid]<=y&&b[mid+1]>y)
{
s2+=(mid+1)*2;
s2+=(m-1-mid)*3;
break;
}
else
{
if(b[mid]<=y)
lb=mid;
else
ub=mid;
}
if(lb==ub)
break;
}
}
//更新得分差
if(s1-s2>score[0]-score[1])
{
score[0]=s1;
score[1]=s2;
}
//依题意相等的话找出a得分较高的那一组
else if(s1-s2==score[0]-score[1])
{
if(s1>score[0])
{
score[0]=s1;
score[1]=s2;
}
}
return true;
}