9.20模拟赛T1[聪明的小偷]

聪明的小偷

(thief.pas/c/cpp)
袋,首先他会先检查每个口袋是不是都有硬币,之后他会计算出第 1 个和第 2 个口袋的硬币数量之和,第 2 个与第 3 个口袋的硬币数量和,如此直到第 n-1 个与第 n 个口袋的硬币数量之和,得到 n-1 个数的序列。如果收藏家发现某个口袋没有硬币,或者他计算得到的序列较上一天相比有变动,那么收藏家就知道肯定有人动了他的硬币。有一个聪明的小偷,他想在收藏家不知道的情
【输入格式】
第一行一个正整数 n,表示口袋的个数。
接下来一行 n 个正整数,第 i 个正整数表示第 i 个口袋里装的硬币数量。
【输出格式】
一行一个正整数,表示答案。
【输入输出样例】
thief.in thief.out
三组:

3
1 2 3
0

4
2 4 6 8
0

5
2 3 4 5 6
1

【样例解释】
第一个样例中,小偷无法在收藏家不知道的情况下移动硬币。
第二个样例中,尽管小偷可以移动硬币,比如移动成 3 3 7 7,但是他仍然
无法拿出硬币。
第三个样例中,小偷将 1,5 口袋的一个硬币移动到 2,4 口袋中,并在口袋 3
中拿出一个硬币即可。
【数据规模与约定】
对于 50%的数据,有 2≤n≤20,每个口袋中硬币数量≤20。
对于 100%的数据,有 2≤n≤999,每个口袋中硬币数量≤10000 且为正整数。

对于这道题,(其实我刚开始就没反应过来,觉得这怎么偷),我们可以先看着解释手推样例,可能刚开始写出来看不出什么,不过我们可以发现一点,
就是在每次小偷第一次移动硬币时,小偷只能移动第一个或最后一个,而且是只能移动到自己后一个或前一个袋子里。
为什么是这样呢?
我们考虑一下收藏家这种查询的性质,因为是两两只和,所以一个数可以影响的和是两个,但是在边界的两个数字只能影响一个,而且若只移动到相邻数字上的话,边界数字影响的和是始终不变的,把第一个位置的数移x到第二个部分里,第一个和第二个的和不变,第二个和第三个的和增加x,后面不变。把最后一个的数移x到倒数第二个上,最后一个和倒数第二个和不变,倒数第二个和倒数第三个和增加x。同时如果我们把第三个数向第四个数移x情况是一样的,那么我们的和增加的x就会向中间聚拢,所有有移钱操作的袋子下标都是奇数,如果n为奇数的话,中间就有 a m i d − 1 , a m i d , a m i d + 1 a_{mid - 1}, a_{mid}, a_{mid + 1} amid1,amid,amid+1这时候 a m i d − 2 和 a m i d + 2 a_{mid - 2}和a_{mid +2} amid2amid+2 都向相邻的 a m i d − 1 , a m i d + 1 a_{mid - 1}, a_{mid + 1} amid1,amid+1移了x钱,这时候 a m i d a_{mid} amid与前后两项的和都增加了x,同时你不能将钱向两边传递了(因为是两边传过来的),这时你就可以从 a m i d a_mid amid中拿出x使两边的和不变。

同时我们可以发现,如果n是偶数,那么在向两边传递的时候是没有一个 a m i d a_{mid} amid可以通过减去x来使两边的和合法。因此偶数时我们是拿不走钱的。
并且当n为奇数时,移钱的下标是奇数,也就是说,在n是奇数的条件下,最多能移的钱 x = m i n ( a i ) , i m o d 2 = = 1 x = min(a_i), i mod 2 == 1 x=minai,imod2==1

代码很简单
C o d e Code Code

#include<bits/stdc++.h>

#define MAXN 100010
#define INF 0x3f3f3f3f

using namespace std;

inline void read(int &s){
	s = 0; int w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar();}
	s *= w; return ;
}

int n;
int a[MAXN];
int ans = INF;

int main()
{
	//freopen("thief.in", "r", stdin);
	//freopen("thief.out", "w", stdout);
	
	read(n);
	if(n % 2 == 0){
		puts("0"); return 0;
	}
	
	for(int i = 1; i <= n; ++i){
		read(a[i]);
		if(i & 1){
			ans = min(ans, a[i]);
		}
	}
	
	printf("%d\n", ans - 1);
	return 0;		
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIGBIGPPT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值