聪明的小偷
(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}
amid−1,amid,amid+1这时候
a
m
i
d
−
2
和
a
m
i
d
+
2
a_{mid - 2}和a_{mid +2}
amid−2和amid+2 都向相邻的
a
m
i
d
−
1
,
a
m
i
d
+
1
a_{mid - 1}, a_{mid + 1}
amid−1,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=min(ai),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;
}