20241031模拟赛题解

T1

题目描述

给定一个圆形蛋糕,被 \(n\) 条切割线分成 \(n\) 个扇形蛋糕块,按照顺时针编号,第 \(i\) 块上有 \(a_i\) 个草莓,第 \(i\) 条切割线到第 \(i+1\) 条切割线之间的部分是第 \(i\) 块蛋糕。

Alice 和 Bob 流选择切割线,假设 Alice 选择了第 \(i\) 条切割线,Bob选择了第 \(j\) 条切割线,\(j\) 不能等于 \(i\)。则 Alice 获得从第 \(i\) 条切割线顺时针到第 \(j\) 条切割线之间的蛋糕,Bob获得剩余蛋糕。Alice 的平均草莓数若大于等于 Bob 的平均草莓数,则 Alice 获胜,否则 Bob 获胜。求使 Alice 必胜的最小切割线编号,不存在则输出 \(-1\)

输入格式

第一行一个正整数 \(n\)

第二行 \(n\) 个正整数 \(a_i\) 表示第 \(i\) 块内的草莓数量。

输出格式

一个整数,即为答案。

样例

样例输入1

3
3 8 5

样例输出1

2

Alice 在 \(3\)\(8\) 之间切一刀,Alice要么会拿到 \(8\) 要么会拿到 \(8\)\(5\),都可以获胜。

数据范围

对于所有数据 \(1<n≤500000,1≤ai≤500000\)

对于 \(50 \%\) 的数据 \(n≤1000\)

对于 \(100 \%\) 的数据无特殊限制。

解法说明

可将每个 \(a_i\) 转化为其与所有数字的平均值之间的差,对新的 \(a_i\) 做前缀和,则当 Alice 选 \(i\),Bob 选 \(j\) 时,如 \(sum_{j-1} - sum_{i-1} ≥ 0\),则 Alice 胜。故 Alice 应选 \(sum_{i-1}\) 最小的点后面的切割线,此时无论 Bob 如何选择都必败。

通过代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=5e5+10;

namespace IO{
	inline int read(){
		int x=0,f=1;char ch=getchar();
		while(ch<'0'||ch>'9') f=(ch=='-'?-1:f),ch=getchar();
		while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
		return x*f;
	}

	inline void write(int x){
		if(x<0) putchar('-'),x=-x;
		if(x>9) write(x/10);
		putchar(x%10+'0');
	}
}using namespace IO;

namespace code{
	int n,a[N],sum[N],ans;

	void solve(){
		n=read();
		for(int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i];
		for(int i=1;i<=n;i++) a[i]=a[i]*n-sum[n];
		for(int i=1;i<n;i++) sum[i]=sum[i-1]+a[i],ans=(sum[i]<sum[ans]?i:ans);
		write(ans+1);
	}
}

signed main(){
	code::solve();
	return 0;
}

T2

题目描述

游乐园有 \(n\) 个项目,第 \(i\) 个项目直接排队要 \(a_i\) 分钟,使用优速通需要排队 \(b_i\) 分钟。你有 \(k\) 张优速通票,也就是意味着你可以选不超过 \(k\) 个项目使用优速通。你一共有 \(t\) 分钟,这里忽略除了排队以外的其他时间。你想知道你最多可以玩多少个不同的项目。

输入格式

第一行三个正整数 \(n\)\(k\)\(t\)

接下来 \(n\) 行,每行两个正整数 \(a_i\)\(b_i\)

输出格式

一个整数,即最多能玩的项目数量。

样例

样例输入1

5 2 20
7 4
10 8
3 3
8 7
9 5

样例输出1

4

数据范围

对于所有数据 \(1≤k≤n≤2×10^5,1≤T≤10^{18}, 1≤b_i≤a_i≤10^{12}\)

对于 \(20\%\) 的数据:\(n≤10\)

对于 \(50\%\) 的数据:\(n≤1000\)

对于 \(100\%\) 的数据:无特殊限制。

解法说明

反悔贪心。

显然,前 \(k\) 个肯定是 \(b_i\) 能选几个是几个。如果选完后 \(t>0\),则应增加一些项目,有以下两种可能:

  1. 新加一个 \(a_i\)
  2. 新加一个 \(b_i\),并将一个选过的 \(b_j\) 换成 \(a_j\)

此时我们可以开三个堆,一个存储未选过的 \(a_i\),另一个存储未选过的 \(b_i\),最后一个存储选过的 \(a_j - b_j\)。记三个堆堆顶分别为 \(u\)\(v\)\(w\),则如果 \(u<v+w\) 选择第一种,否则选择第二种,不停循环直到 \(t<0\) 为止。

通过代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define PII pair<int,int>
#define mp make_pair
const int N=2e5+10;

namespace IO{
	inline int read(){
		int x=0,f=1;char ch=getchar();
		while(ch<'0'||ch>'9') f=(ch=='-'?-1:f),ch=getchar();
		while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
		return x*f;
	}

	inline void write(int x){
		if(x<0) putchar('-'),x=-x;
		if(x>9) write(x/10);
		putchar(x%10+'0');
	}
}using namespace IO;

namespace code{
	int n,k,t,ans;
	bool vis[N];
	
	struct node{
		int a,b;
	}a[N];
	
	priority_queue<PII,vector<PII>,greater<PII> > q1,q2,q3;
	
	bool cmp(node x,node y){
		return x.b<y.b;
	}

	void solve(){
		n=read(),k=read(),t=read();
		for(int i=1;i<=n;i++) a[i].a=read(),a[i].b=read();
		sort(a+1,a+n+1,cmp);
		for(int i=1;i<=k&&t>=0;i++,ans++) t-=a[i].b,vis[i]=1;
		if(t<0) return write(ans-1),void();
		for(int i=1;i<=n;i++){
			if(!vis[i]) q1.push(mp(a[i].a,i)),q2.push(mp(a[i].b,i));
			else q3.push(mp(a[i].a-a[i].b,i));
		}
		while(t>0){
			int x=q1.top().second,y=q2.top().second,u,v,w;
			while(vis[x]) q1.pop(),x=q1.top().second;
			while(vis[y]) q2.pop(),y=q2.top().second;
			ans++,u=q1.top().first,v=q2.top().first,w=q3.top().first;
			if(u<v+w) q1.pop(),vis[x]=1,t-=u;
			else q2.pop(),q3.pop(),vis[y]=1,t-=v+w,q3.push(mp(a[y].a-a[y].b,y));
		}
		write(t<0?--ans:ans);
	}
}

signed main(){
	code::solve();
	return 0;
}
posted @ 2024-10-31 17:30  Alexxtl  阅读(50)  评论(0编辑  收藏  举报