Codeforces1561B Charmed by the Game (思维)

题目链接: Charmed by the Game

大致题意

A和B玩一个游戏, 两个人轮流发球(最初时, 可以A先发, 也可以B先发).

如果A发球, B接住了, 称为"破发", 反之依然.
如果A发球, B没接住, A赢. 若B接住了, B赢. 反之依然.

现给出A和B胜利的次数, 问可能出现的破发情况有多少种, 并输出每种情况下的破发次数.

解题思路

思维 (感觉这个题思维量真的高)

首先我们考虑, 其实发球情况只有两种, 一种是A先手, 另外一种是B先手. 我们不妨讨论A先手发球的情况, 另外一种同理可得.

我们不妨先求出最大破发数. 即: 如果当前是A发球, 看看B是否还能胜利, 如果能, 记录破发. 反之亦然.

然后考虑减小破发数: 假设当前A发球, B破发了, 我们改变结果, 变成A发球, B未破发. 此时胜利情况并不符合题意, 因此我们应在A的胜局中选出一局, 让B赢. 考虑到A胜局有两种情况, 一种是B发球, A破发的情况, 另外一种是A发球, B未破发的情况. 如果我们修改第二种情况, 并不能减小破发数, 因此我们只能修改第一种情况. 这样, 我们发现当前情况的破发数, 比原先减少了2.

我们发现: 如果想要减少破发数, 我们至少需要改变两场A破发, 且B也破发的局面. 那么最大可以减小的次数即为: m i n ( A 破 发 次 数 , B 破 发 次 数 ) min(A破发次数, B破发次数) min(A,B).


我看有大佬用 01 01 01序列抽象出了模型, 这里也可以简单说一下(因为代码也是这样实现的):

假设我们发球序列用 1 1 1表示A发球, 0 0 0表示B发球. 结果序列用 1 1 1表示破发, 0 0 0表示未破发.

两种情况下的发球序列都是固定的, 我们无法更改. 我们只能改变结果序列.

我们要减小破发数, 相当于把结果序列中的 1 1 1变成 0 0 0, 并且还需要保证胜利情况不改变. 因此我们必须改变偶数次结果序列, 使得序列中的 1 1 1变成 0 0 0. 且每两次改变, 应该改变A和B两个人的破发结果.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 2E5 + 10;
int a[N];

set<int> st;
void fact(int n, int m, bool flag) {
	int all = n + m;
	rep(i, all) a[i] = (i & 1) ^ flag;

	int ba = 0, bb = 0; //记录A和B的破发次数
	rep(i, all) {
		if (a[i] == 1) { //A发球
			if (m) m--, bb++;
			else n--;
		}
		else {
			if (n) n--, ba++;
			else m--;
		}
	}

    int fmax = ba + bb;
	st.insert(fmax);
	int can = min(ba, bb);
	rep(i, can) st.insert(fmax - i * 2);
}
int main()
{
    int t; cin >> t;
    while (t--) {
    	int n, m; scanf("%d %d", &n, &m);

    	st.clear();
    	fact(n, m, 0);
	    fact(n, m, 1);

	    printf("%u\n", st.size());
		for (auto& op : st) printf("%d ", op); puts("");
    }

    return 0;
}

END

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逍遥Fau

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

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

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

打赏作者

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

抵扣说明:

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

余额充值