题意:
两个人玩石头剪刀布游戏,第一个人可以出 a 1 a_1 a1个石头, a 2 a_2 a2个剪刀, a 3 a_3 a3个布;第二个人可以出 b 1 b_1 b1个石头, b 2 b_2 b2个剪刀, b 3 b_3 b3个布。其中, a 1 + a 2 + a 3 = b 1 + b 2 + b 3 = n a_1 + a_2 + a_3 = b_1 + b_2 + b_3 = n a1+a2+a3=b1+b2+b3=n。问第一个人最少赢多少次,最多赢多少次。
思路
最多赢多少次,比较容易想。这种情况就是自己每次出牌,对方都会出被自己克制的牌。那么赢的场次就是,
a
n
s
1
=
m
i
n
(
a
1
,
b
2
)
+
m
i
n
(
a
2
,
b
3
)
+
m
i
n
(
a
3
,
b
1
)
ans1 = min(a_1,b_2) + min(a_2,b_3) + min(a_3,b_1)
ans1=min(a1,b2)+min(a2,b3)+min(a3,b1)
最少赢多少次,就是自己每次出牌,对方都会出克制自己的牌,或者打平的牌。但是如果直接这么去写的话,需要讨论很多情况,因此我们需要进一步思考。如果对方一直克制自己或者与自己打平的话,那么最后的时候会出现什么情况呢?就是最后自己剩下一种牌,若干张;对方也只剩下一种牌,若干张。并且自己的牌是克制对方的牌的。
以最后剩下石头和剪刀为例。因为我们分析的是最少赢多少次,那肯定在只剩下石头(剪刀)之前,可以尽可能地多消耗剪刀,这样可以使得最后赢的更少。那么我们可以干脆不看
b
1
b_1
b1和
b
3
b_3
b3,直接消耗
b
2
b_2
b2。那么最后第二个人剪刀剩下的数量是
b
2
−
a
2
−
a
3
b_2 - a_2 - a_3
b2−a2−a3。
如果只剩下剪刀(布)或者布(石头),同理可得。那么现在就得到了
3
3
3个数字,分别为
b
2
−
a
2
−
a
3
b_2 - a_2 - a_3
b2−a2−a3、
b
1
−
a
1
−
a
2
b_1 - a_1 - a_2
b1−a1−a2、
b
3
−
a
1
−
a
3
b_3 - a_1 - a_3
b3−a1−a3。但是这里会有一个问题,就是有可能这三个数是负数,那么就根本不会剩下了,那么最后分别只剩下一种牌,并且第一个人的克制第二个人的情况就不会出现了。如果是这样的话,那就最少赢
0
0
0次。最后的答案就是这三个数以及
0
0
0取最大值即可。
如果三个数中有多个正数,那么答案是多少呢?其实,这里有一个性质,那就是这三个数,最多只有一个正数。下面对这个结论做一个简单的证明。不妨设
b
2
−
a
2
−
a
3
>
0
b_2 - a_2 - a_3 > 0
b2−a2−a3>0,移项可得
b
2
>
a
2
+
a
3
b_2 > a_2 + a_3
b2>a2+a3,由于
a
1
+
a
2
+
a
3
=
b
1
+
b
2
+
b
3
=
n
a_1 + a_2 + a_3 = b_1 + b_2 + b_3 = n
a1+a2+a3=b1+b2+b3=n,则
a
1
>
b
1
+
b
3
a_1 > b_1 + b_3
a1>b1+b3,那么
b
1
−
a
1
−
a
2
<
0
,
b
3
−
a
1
−
a
3
<
0
b_1 -a_1-a_2<0,b_3-a_1-a_3<0
b1−a1−a2<0,b3−a1−a3<0。证毕!
代码
#include <iostream>
#include <cstdio>
using namespace std;
int n;
int a[4], b[4];
int main()
{
cin >> n;
for(int i=1;i<=3;i++) cin >> a[i];
for(int i=1;i<=3;i++) cin >> b[i];
int ans1 = max(max(0, b[3]-a[3]-a[1]), max(b[2]-a[2]-a[3], b[1]-a[1]-a[2]));
int ans2 = min(a[1],b[2]) + min(a[2],b[3]) + min(a[3],b[1]);
cout << ans1 << ' ' << ans2 << endl;
return 0;
}