Vasya follows a basketball game and marks the distances from which each team makes a throw. He knows that each successful throw has value of either 2 or 3 points. A throw is worth 2 points if the distance it was made from doesn't exceed some value of d meters, and a throw is worth 3 points if the distance is larger than d meters, where d is some non-negative integer.
Vasya would like the advantage of the points scored by the first team (the points of the first team minus the points of the second team) to be maximum. For that he can mentally choose the value of d. Help him to do that.
The first line contains integer n (1 ≤ n ≤ 2·105) — the number of throws of the first team. Then follow n integer numbers — the distances of throws ai (1 ≤ ai ≤ 2·109).
Then follows number m (1 ≤ m ≤ 2·105) — the number of the throws of the second team. Then follow m integer numbers — the distances of throws of bi (1 ≤ bi ≤ 2·109).
Print two numbers in the format a:b — the score that is possible considering the problem conditions where the result of subtractiona - b is maximum. If there are several such scores, find the one in which number a is maximum.
3 1 2 3 2 5 6
9:6
5 6 7 8 9 10 5 1 2 3 4 5
15:10
这道题的意思是选择正确的得分分界线保证A队得分num1-B队得分num2最大,如果有多个比分满足要求,则选择A队得分最大的比分。
首先对两个队伍的得分进行排序是显然的。
这道题由于选择得分分界线以后,小于这个分数的得2分,多于这个分数的得3分。
所以最开始可以把A队比分置为3*n,B队比分置为3*m。然后3*(n-m)这个比分的差值就是一个定值,然后就是选择A队需要减去多少分,B队需要减去多少分。即选择正确的分界线,然后只需要统计A中小于这个分数的人数和B中小于这个分数的个数。
最开始我只想的是判断a[0]元素在B数组中的位置,用到了lower_bound函数,然后判断b[0]元素在A数组中的位置,然后比较这两个数的大小,如果a[0]在b中的位置之前的元素的个数大于b[0]在a数组中的位置之前的元素个数,则b队得分减去的分数就比a队得分减去的分数要多。
这样是不严谨的。。因为并不一定要在这两个地方进行分数分界。比如
a: 5 8
b:1 2 3 45 6 7 8 9 10
初始分数为6:30 (-24)
如果选择a[0]=5这个分数为分界线,则比分为5:25(-20),如果选择a[1]=8这个分数为分界线,则比分为4:22(-18)。如果选择10作为分界线,则比分为4:20(-15),这个比分差值是最小的。。
这个的分析就可以知道仅仅判断a[0]和b[0]元素是不严谨的。
应该整体遍历一遍,在时间复杂度的要求上还是可以说的过去的。不会导致超时。
for(int i=0;i<n;i++)
{
int t=lower_bound(b,b+m,a[i])-b;
if(3*n-3*m-i+t>ans)
{
ans=3*n-3*m+t;
num=t;pos=i;
}
}
printf("%d:%d\n",3*n-pos,3*m-num);
这样逐次判断a[i]在b数组中的位置也是不全面的。而且3*n-i与3*m-t这个计算也有问题。
关于搜索到底使用upper_bound还是使用lower_bound,还有困惑就是搜索的时候到底是搜索a[i]还是a[i]-1。而题目要求的是小于等于分界线的得分值为2分,大于这个分数为3分。最开始初始分数为3*n,3*m。这个相当于是把分界线置为小于两个数组中最小值的任何数。然后可以把每个数当作分界线。其实关于搜索a[i]和a[i]-1的问题的实质就是小于等于和小于的问题。
这样直接把a[i]当成分界线,该队得分就要减去该队所有分数小于等于a[i[的分数的总个数。
关于upper_bound是找到大于这个数的第一个位置,它之前位置的所有数就是小于等于所要寻找的数的。lower_bound是要找到大于等于这个数的第一个位置。
关于对某个数的查找可以用线性查找,也可以用二分查找,都不会超时。
将a,b两个数组元素分类并存在一个数组中,对数组从前到后进行扫描,遇到A数组元素对a的值减1,遇到b数组元素对b的值减1。这样做相当于是对分界线进行逐一枚举。
还有一种方法是不用将a,b两个数组中的元素保存在一个数组中,初始将a,b两数组的值置为2*n和2*m。然后对a,b数组从后往前扫描。这种方法一直没想明白什么意思。我试着按这种方法从前向后扫描就会出错。。从前到后扫描还需要考虑数组元素相等的情形,而且对a,b数组都得从前到后扫描才行。
参考代码
(将a和b两个数组合成一个数组,枚举分界线)
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#define pb push_back
#define mp make_pair
using namespace std;
typedef pair<int,int> p;
vector<p> v;
int main()
{
//ios_base::sync_with_stdio(0);
int n,m;
while(~scanf("%d",&n))
{
int x;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
v.pb(mp(x,0));
}
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d",&x);
v.pb(mp(x,1));
}
sort(v.begin(),v.end());
int n1=3*n,n2=3*m,x1=n1,x2=n2;
for(int i=0;i<n+m;i++)
{
if(v[i].second) x2--;
else x1--;
if((x1-x2)>(n1-n2))
n1=x1,n2=x2;
}
printf("%d:%d\n",n1,n2);
}
}
(从后往前遍历)(这个有点不太明白实质。。自己写的后边那个从前往后的程序要复杂一些。。)
<span style="font-size:14px;">#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[maxn],b[maxn];
int main()
{
//ios_base::sync_with_stdio(0);
int n,m;
while(~scanf("%d",&n))
{
int x;
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);
int n1=2*n,n2=2*m,x1=n1,x2=n2;
int i=n-1,j=m-1;
while(i>=0||j>=0)
{
if(i>=0)
{
x1++;
while(j>=0&&a[i]<=b[j])
j--,x2++;
i--;
}
else
{
x2++;
j--;
}
if((x1-x2)>=(n1-n2))
{
n1=x1;
n2=x2;
}
}
printf("%d:%d\n",n1,n2);
}
}</span>
(从前向后遍历)
<span style="font-size:14px;">#include<cstdio>
#include<iostream>
#include<algorithm>
#define maxn 1000100
using namespace std;
int a[maxn],b[maxn];
int main()
{
int n,m;
while(~scanf("%d",&n))
{
int x;
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);
int n1=3*n,n2=3*m,x1=n1,x2=n2;
int i=0,j=0;
while(i<n||j<m)
{
if(i<n)
{
int t=a[i];
while(i<n&&a[i]==t)
i++,x1--;
i--;
while(j<m&&a[i]>=b[j])
x2--,j++;
i++;
}
else
{
x2--;
j++;
}
if((x1-x2)>(n1-n2))
{
n1=x1;
n2=x2;
}
if((x1-x2)==(n1-n2))
{
if(x1>n1)
n1=x1,n2=x2;
}
//printf("%d %d\n",x1,x2);
}
//printf("\n");
x1=3*n,x2=3*m,i=0,j=0;
while(i<n||j<m)
{
if(j<m)
{
int t=b[j];
while(j<m&&b[j]==t)
j++,x2--;
j--;
//printf("x2=%d\n",x2);
while(i<n&&b[j]>=a[i])
x1--,i++;
j++;
}
else
{
x1--;
i++;
}
if((x1-x2)>(n1-n2))
{
n1=x1;
n2=x2;
}
if((x1-x2)==(n1-n2))
{
if(x1>n1)
n1=x1,n2=x2;
}
//printf("x1=%d x2=%d\n",x1,x2);
}
printf("%d:%d\n",n1,n2);
}
}</span><span style="font-weight: bold; font-size: 32px;">
</span>