20241031 校内模拟赛 T1、T2 题解

T1

题目描述

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

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

输入格式

第一行一个正整数 nnn

第二行 nnn 个正整数 aia_iai 表示第 iii 块内的草莓数量。

输出格式

一个整数,即为答案。

样例

样例输入1

3
3 8 5

样例输出1

2

Alice 在 333888 之间切一刀,Alice要么会拿到 888 要么会拿到 888555,都可以获胜。

数据范围

对于所有数据 1<n≤500000,1≤ai≤5000001<n≤500000,1≤ai≤5000001<n500000,1ai500000

对于 50%50 \%50% 的数据 n≤1000n≤1000n1000

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

解法说明

可将每个 aia_iai 转化为其与所有数字的平均值之间的差,对新的 aia_iai 做前缀和,则当 Alice 选 iii,Bob 选 jjj 时,如 sumj−1−sumi−1≥0sum_{j-1} - sum_{i-1} ≥ 0sumj1sumi10,则 Alice 胜。故 Alice 应选 sumi−1sum_{i-1}sumi1 最小的点后面的切割线,此时无论 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

题目描述

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

输入格式

第一行三个正整数 nnnkkkttt

接下来 nnn 行,每行两个正整数 aia_iaibib_ibi

输出格式

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

样例

样例输入1

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

样例输出1

4

数据范围

对于所有数据 1≤k≤n≤2×105,1≤T≤1018,1≤bi≤ai≤10121≤k≤n≤2×10^5,1≤T≤10^{18}, 1≤b_i≤a_i≤10^{12}1kn2×105,1T1018,1biai1012

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

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

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

解法说明

反悔贪心。

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

  1. 新加一个 aia_iai
  2. 新加一个 bib_ibi,并将一个选过的 bjb_jbj 换成 aja_jaj

此时我们可以开三个堆,一个存储未选过的 aia_iai,另一个存储未选过的 bib_ibi,最后一个存储选过的 aj−bja_j - b_jajbj。记三个堆堆顶分别为 uuuvvvwww,则如果 u<v+wu<v+wu<v+w 选择第一种,否则选择第二种,不停循环直到 t<0t<0t<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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值