题目
oxx 和 Xiejiadong 在玩一个双人旋转赛车的小游戏。
他们将进行一些比赛。每局比赛必须按顺序进行,胜者会得到该局对应的分数 xi。
由于 oxx 技艺不精(每局都可以由 Xiejiadong 决定胜负),
因此他给自己设置了初始分数 k,希望自己能够一直领先 Xiejiadong。
不过 Xiejiadong 识破了 oxx 的诡计,现在 Xiejiadong 想知道自己至少需要赢几局才可以使得自己能够在某一时刻的比分不落后于 oxx。
若无法达到则输出 −1。
n<=1e6,k<=1e9,1<=xi<=1e9
思路来源
https://acm.ecnu.edu.cn/blog/entry/239/?tdsourcetag=s_pctim_aiomsg
题解
题解写的够优秀了,我就不BB了,直接粘代码
代码1(解法2:单指针,O(nlogn))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int n,k,Rank[maxn];
int tmp[maxn];//临时储存数量
int pointer,now;//指针(pointer,n] 当前k个值都在后面
int l,r;
struct node
{
int a,id,rk;
}e[maxn];
bool operator<(node a,node b)
{
return a.a<b.a||(a.a==b.a&&a.id<b.id);
}
bool cmp(node a,node b)
{
return a.id<b.id;
}
bool ok(int mid,int k)
{
//printf("mid:%d\n",mid);
ll sum=0,score=k;
pointer=now=0;
memset(tmp,0,sizeof tmp);
for(int i=1;i<=n;++i)
{
if(e[i].rk>pointer&&now<=mid)
{
tmp[e[i].rk]++;
now++;
sum+=Rank[e[i].rk];
}
else score+=Rank[e[i].rk];
while(now>mid&&pointer<n)
{
pointer++;
if(tmp[pointer])
{
tmp[pointer]--;
now--;
score+=Rank[pointer];
sum-=Rank[pointer];
}
}
//printf("rk:%d v:%lld\n",e[i].rk,e[i].a);
//printf("sum:%lld score:%lld\n",sum,score);
if(sum>=score)return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
{
scanf("%d",&e[i].a);
e[i].id=i;
}
sort(e+1,e+n+1);
for(int i=1;i<=n;++i)
{
e[i].rk=i;
Rank[i]=e[i].a;
}
sort(e+1,e+n+1,cmp);
l=0;r=n;
while(l<r)
{
int mid=(l+r)/2;
if(!ok(mid,k))l=mid+1;
else r=mid;
}
if(!ok(l,k))puts("-1");
else printf("%d\n",l);
return 0;
}
代码2(解法3:贪心)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
//贪心 每次把最小的还给oxx
//优先队列表示在队列中的 是xiejiadong要选的
priority_queue<ll,vector<ll>,greater<ll> >q;
ll sum1,sum2,a[maxn];
int n,now,ans;
int main()
{
scanf("%d%lld",&n,&sum1);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
ans=n+1;
for(int i=1;i<=n;++i)
{
sum2+=a[i];
q.push(a[i]);
now++;//now=q.size()
while(sum2-q.top()>=sum1+q.top())
{
sum2-=q.top();
sum1+=q.top();
q.pop();
now--;
}
if(sum2>=sum1)ans=min(ans,now);
}
printf("%d\n",ans==n+1?-1:ans);
return 0;
}
代码3(解法4:树状数组)