Educational Codeforces Round 158 (Rated for Div. 2) A-D

A. Line Trip

题目链接

题意

有一条路,可以用一条数字线来表示。您位于数轴上的点 0 ,您想从点 0 移动到点 x ,然后再回到点 0 。你开车旅行,每行驶 1 单位距离要消耗 1 升汽油。

当您在点 0 启动时,您的汽车已加满油(其油箱包含最大可能的燃料量)。有 n个加油站,位于点 a1,a2,…,an 。当你到达加油站时,你给你的车加满油。

请注意,您只能在加油站加油, 0 和 x 点没有加油站。您必须计算汽车油箱的最小可能容量(以升为单位)

这将允许您从点 00移动到点 x ,然后再返回到点 0 。

分析

计算每个加油站之间的最大距离即可,需要注意到达终点后还需要返回起点,所以需要再计算最后一个加油站到终点后再从终点返回最后一个加油站所需的距离

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>

#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

typedef pair<int,int>PII;
const int N=110;
ll f[N];
	
	
int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,m;
		cin>>n>>m;
		for(int i=1;i<=n;i++) cin>>f[i];
		ll ans=-1e9;
		for(int i=0;i<n;i++) ans=max(ans,f[i+1]-f[i]);
		ans=max(ans,2*(m-f[n]));
		cout<<ans<<endl;
	}
	
	
	return 0;
}

B. Chip and Ribbon

题目链接

题意

功能区分为 n 个单元格,从左到右编号为 1 到 n 。最初,在每个单元格中写入整数 0 。单尾鱼用芯片玩游戏。游戏由几个回合组成。

在第一圈中,单果皮将芯片放置在带的第5个单元中。在每个回合期间,除第一回合外,Monocarp恰好执行以下两个动作中的一个:

将芯片移动到下一个单元(即,

 如果芯片在单元 i 中,则将其移动到单元 i+1 。如果芯片在最后一个单元中,则该动作是不可能的

-选择任意单元 x 并将芯片传送到该单元中。可以选择芯片当前所在的小区。在每一圈结束时,写入具有芯片的单元中的整数增加 1 。

Monocarp的目标是进行一些转弯,使第 1 个单元格包含整数 c1 ,第 2 个单元格包含整数 c2,..

,第 n 个单元格包含整数 cn 。他想尽可能少地传送芯片。帮助Monocarp计算他必须传送芯片的最小次数。

分析

如果一个单元格中的数字比其之前的单元格中的数字小的话,那么其一定可以由前一个单元格向后移动得到,反之若一个单元格比前面单元格中的数字大,那么其不能由前面单元格向后移动得到芯片,只能通过传送芯片来得到芯片,故遍历数组,累加前后元素之差即可

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>

#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

typedef pair<int,int>PII;
const int N=2e5+10;
int a[N];

	
int main()
{
	int t;cin>>t;
	while(t--)
	{
		
		int n;cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		ll ans=0;
		a[0]=0;
		for(int i=1;i<=n;i++)
		{
			ans+=max(a[i]-a[i-1],0);
		}
		cout<<ans-1<<endl;//开局是芯片处于1单元格,相当于白送一次
	}
	
	
	return 0;
}

C. Add, Divide and Floor

题目链接

题意

您将得到一个整数数组 a1,a2,…,an ( 0≤ai≤1e9 )。在一个操作中,可以选择整数 x ( 0≤x≤1e18 )对于从 1到 n 的所有 i ,用 ⌊(ai+x/)2⌋替换 ai,⌊y⌋表示将 y向下舍入到最接近的整数。请注意,数组的所有元素在每次操作时都会受到影响。打印使数组的所有元素相等所需的最小操作数。

如果操作数小于或等于 n ,则为每个操作打印所选的 x 。

如果有多个答案,请打印其中任何一个。

分析

因为答案与数组的顺序无关,所以我们考虑将数组排序,因最后的答案要求所有的元素都相等,可以想到,当操作若干次之后,若数组中的最小值与最大值相等,那么全部元素一定都相等,若我们每次都选择最小值为x,那么最小值将不会发生改变,而其余的值都会不断缩小,最大值也不断向最小值逼近,直至最大值与最小值相等

最猜的一集,(雾)

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>

#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

typedef pair<int,int>PII;
const int N=2e5+10;
int f[N];
int res[N];
	
int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n;cin>>n;
		for(int i=1;i<=n;i++) cin>>f[i];
		
		sort(f+1,f+n+1);
		int l=f[1],r=f[n];
		vector<int>ans;
		while(l<r)
		{
			r=(l+r)/2;
			ans.push_back(l);
		}
		cout<<ans.size()<<endl;
		if(ans.size()>0 && ans.size()<=n)
		{
			for(int i=0;i<ans.size();i++) cout<<ans[i]<<" ";
			cout<<endl;
		}
	}
	
	
	return 0;
}

D. Yet Another Monster Fight

题目链接

题意

有n只怪物站成一排,一个巫师决定施展连锁闪电咒来击败所有怪物,咒语的第一个目标总是怪物 i。对于除第一个目标之外的每个目标,闪电链将选择一个随机怪物,该怪物未被咒语击中,并且与其中一个已被击中的怪物相邻。所以,每个怪物都会被击中一次。第一只被法术击中的怪物受到 x 伤害,第二只受到 (x−1) 伤害,第三只受到 (x−2) 伤害,以此类推。巫师想要只施展一次咒语就打败所有的怪物,请你确定最小的法术强度,以至于无论咒语的攻击顺序是什么,都能保证一次击败所有怪物

分析

对于第i个怪物,可以将所有怪物分为三个区间,i号怪物的左边,i号怪物,i号怪物的右边

我们记i号怪物左边有x只怪物,右边有y只怪物

由于闪电链的随即攻击相邻怪物,那么对于i号怪物,如果攻击从左边到来,那么最坏的情况就是左边的x只怪物全部被攻击之后i号怪物才被攻击到,那么此时i号怪物应最少受到a[i]+i-1点伤害(a[i]为i号怪物的生命值,i-1为i的左面有i-1只怪物,由于伤害每次递减1),同理如果攻击从右边到来,那么最坏的情况就是右边的y只怪物全部被攻击之后i号怪物才被攻击,此时i号怪物应最少受到a[i]+n-i点伤害(i的右边有n-i只怪物),那么我们可以用两个数组分别记录每个怪物从左右最小受到的伤害,然后用max前后缀数组计算保证每个区间怪物能够死亡所受到的最小伤害,最后枚举第一个雷击的怪物,取最小值即可

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>

#define ll long long
#define inf 0x3f3f3f3f
using namespace std;

typedef pair<int,int>PII;
const int N=3e5+10;
ll l[N];//i点左边区间的最大限制
ll r[N];//i点右边区间的最大限制
ll a[N];
ll ans=1e18;	
	
int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++)//i点左右方向受到的最小致命攻击
	{
		l[i]=a[i]+i-1;//最坏的情况是打完左边所有怪物再打i
		r[i]=a[i]+n-i;//最坏情况是打完右边所有怪物再打i
	}
	//现在只保证了i点无论受到左右哪个方向的攻击都会死
	//还需要保证i点死的同时,其左右区间内的怪物都会死
	for(int i=2;i<=n;i++) r[i]=max(r[i],r[i-1]);//右区间的最大伤害
	for(int i=n-1;i>=1;i--) l[i]=max(l[i],l[i+1]);//左区间的最大伤害
	
	for(int i=1;i<=n;i++)//枚举雷击位置
	{
		ans=min(ans,max(a[i],max(l[i-1],r[i+1])));
	}
	cout<<ans;
	return 0;
}

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值