组队竞赛
内存限制: 256 Mb时间限制: 1000 ms
题目描述
有nn同学想要参加小爱组建的一支信息学竞赛队伍,每位同学有能力值a_iai与热情度b_ibi。
小爱认为,如果队伍当中,能力值最大与能力值最小选手之间,能力差值大于给定XX,会导致能力差距过大、不利于团队的学习与凝聚力。因此,请你帮助小爱计算下,如何选择队伍的选手,才能使所有选手的能力差值小于等于X,且热情度最大。
输入格式
输入第一行,一个正整数nn,表示有n位选手
接下来nn行,每行两个正整数a_i,b_iai,bi表示每位选手的能力值与热情度。
最后一行,一个正整数XX,表示小爱希望的能力差值上限输出格式
输出一个整数,表示满足条件的情况下,最大热情度的值
数据范围
- 对于30\%30%的数据,1 ≤ n ≤ 1001≤n≤100
- 对于60\%60%的数据,1≤ n ≤ 10^41≤n≤104
- 对于100\%100%的数据,1≤n≤10^5,1≤d≤10^9,1≤a_i,b_i ≤ 10^9,1≤n≤105,1≤d≤109,1≤ai,bi≤109
样例数据
输入:
5
10 21
20 34
30 27
40 89
50 54
20输出:
170
说明:
选第3、4、5个选手。
能力值分别为30、40、50,不超过50-30=20给定的能力差值上限20
此时热情度为27+89+54=170
题意大概是:在满足选中人 最大与最小相差不超过X的情况下,和最大。(我后面代码a与b数组名颠倒了,特告知)
方法1:直接爆搜,时间复杂度O(n!),实测30分。
#include <bits/stdc++.h>
using namespace std;
int n,b[1000010],a[1000010],ans,y;
void dfs(int x,int s,int a1,int a2){
if(x==n){
if(s>ans)ans=s;
return;
}
for(int i=x+1;i<=n;++i){
int ltv=a1,lvt=a2;
if(b[i]-ltv>y||lvt-b[i]>y)continue;//不满足,跳过
if(b[i]<ltv)ltv=b[i];
if(b[i]>lvt)lvt=b[i];//修改最大最小值
dfs(i,s+a[i],ltv,lvt);//选中
}
if(s>ans)ans=s;//此时终止搜索,不再继续选
return;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i)cin>>b[i]>>a[i];
cin>>y;
for(int i=1;i<=n;++i)dfs(i,a[i],b[i],b[i]);
cout<<ans<<endl;
return 0;
}
但是有太多没必要的搜索了,需要优化。(就不详细讲了)
方法2:先冒泡排序,再计算可取到的最大和,可以避免无谓的时间浪费。实测60分。
#include <bits/stdc++.h>
using namespace std;
int n,b[1000010],a[1000010],ans=-1,y;
int main(){
cin>>n;
for(int i=1;i<=n;++i)cin>>b[i]>>a[i];
cin>>y;
for(int i=1;i<=n;++i)
for(int j=1;j<=n-i;++j)
if(b[j]>b[j+1]){
swap(a[j],a[j+1]);
swap(b[j],b[j+1]);
}
//排序
for(int i=1;i<=n;++i){
int ss=0;//用于计算和
for(int j=i;j<=n;++j){
if(b[j]-b[i]>y)break;//差大于y,跳出
ss+=a[j];
}
if(ss>ans)ans=ss;
}
cout<<ans<<endl;
return 0;
}
方法3:优化2号方案,维护前缀和,减少枚举。期望得分:100分,实测60分。
#include <bits/stdc++.h>
using namespace std;
int n,b[1000010],a[1000010],ans=-1,y;
int main(){
cin>>n;
for(int i=1;i<=n;++i)cin>>b[i]>>a[i];
cin>>y;
for(int i=1;i<=n;++i)
for(int j=1;j<=n-i;++j)
if(b[j]>b[j+1]){
swap(a[j],a[j+1]);
swap(b[j],b[j+1]);
}
int s=1,ss=0;
for(int i=1;i<=n;++i){
for(int j=s;j<=n;++j){
if(b[j]-b[i]>y){
s=j;//记下编号
break;
}
if(j==n)s=n+1;//枚举到尽头特判标记
ss+=a[j];//加上新的a_j
}
ss-=a[i-1];//减去超出范围的a_i
if(ss>ans)ans=ss;
}
//总的来说是维护前缀和
cout<<ans<<endl;
return 0;
}
实测仍是60分。呜呼!!!
问题在哪???一看,前面的冒泡直接超了,后面的优化自然也没有意义了。
何以解忧???唯有sort。
…………但是无法用其给二维数组排序,所以要动用结构体了
方法4:用结构体以使用时间复杂度为O(n log n)的sort排序,用方案2+结构体,70分(有一个点720ms可以卡过)要注意long long,否则会爆。
#include <bits/stdc++.h>
using namespace std;
long long n,ans=-1,y;
struct nod{
int pos,find;
};
nod a[100010];
bool check(nod s,nod o){
return s.pos<o.pos;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i].pos>>a[i].find;
cin>>y;
sort(a+1,a+1+n,check);
for(int i=1;i<=n;++i){
long long ss=0;
for(int j=i;j<=n;++j){
if(a[j].pos-a[i].pos>y){
break;
}
ss+=a[j].find;
}
if(ss>ans)ans=ss;
}
cout<<ans<<endl;
return 0;
}
方法5:方案3+结构体(实测100分)
#include <bits/stdc++.h>
using namespace std;
long long n,ans=-1,y;
struct nod{
int pos,find;//定义结构体
};
nod a[100010];
bool check(nod s,nod o){//因为结构体属于自定义类型,所以要写比较函数
return s.pos<o.pos;//从小到大排
}
int main(){
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i].pos>>a[i].find;
cin>>y;
sort(a+1,a+1+n,check);//排序
long long s=1,ss=0;
for(int i=1;i<=n;++i){
for(int j=s;j<=n;++j){
if(a[j].pos-a[i].pos>y){
s=j;
break;
}
if(j==n)s=n+1;
ss+=a[j].find;
}
ss-=a[i-1].find;
if(ss>ans)ans=ss;//维护前缀和
}
cout<<ans<<endl;
return 0;
}