解题codeforces 1553C

228 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情

原题地址

codeforces.com/problemset/…

题目大意

由于原题介绍很冗长,所以这里简单化一下:

小明和小红玩游戏,掷硬币,规则是这样的,硬币有正反面,掷到正面就加一分,反面不加分。
一共十把,第一把小明掷,第二把小红掷,第三把小明掷,第四把小红掷,,,,,,
第九把小明掷,第十把小红掷。
如此这般,最后看谁的分数多,谁就胜利。

谁胜利不重要,我们要解决的问题是,到第几把结束之后,就不用接着玩了,因为结局已经注定是小明或者小红赢了。

什么意思,比如说,第七把小明掷玩之后,此时小明如果积分是1,小红是3。
后面小明还能掷一次,怎么样也不能反超了,所以比赛可以终止了,八,九,十这三把无需再掷。

题目还没完,现在假设你有一种预知未来的能力,对于这十把游戏来说,你能大概给出一个预测,比如说:

1101?11011

上面十个字符代表你对每一把的预测:

  • 数字1代表,本次相应玩家获得一分
  • 数字0代表,本次相应玩家获得0分
  • 字符?代表,本次无法预知

看上面的例子,除了第五把无法预知,其他的都是明确预知的。

问题来了:在给定十个预测结果的情况下,最少玩几把,就可以宣布比赛终止(因为结果无法逆转了)?

解题思路

由于对于?的理解可能出错,我们来讲解一个例子:

??????????

就是这种,也就是说,你完全无法预知。

不要认为,此时就一定会打完十场。

题目意思是,最少打几场,就是说,只要可能发生的就行。

也就是说,你可以认为?就是随意填写,你可以填0,也可以填1,然后穷举所有情况,找到那个最小的就行。

第一种方法:穷举法

正如上面说的,将里面的?的所有可能性全都穷举一遍,然后看看哪一种,能在最少比赛次数就能终止游戏。

由于穷举法,不好,所以不给代码了。

优化之后

这里基于一个简单的逻辑:

两者分数相差越大,那么就越提前终止比赛。

那么就简单了:

  • 让所有?,都向着小明赢的方向走
  • 让所有?,都向着小红赢的方向走

然后看看上面两种,哪种会让比赛更早结束,即可!

下面给代码(Golang):

func minTime(s string) int {
	var res = 9

	//尽量让小明赢:
	{
		var score0, score1 int
		for loop := 0; loop < 10; loop++ {
			if loop%2 == 0 {
				if s[loop] != '0' {
					score0++
				}
			} else {
				if s[loop] == '1' {
					score1++
				}
			}

			if score0 > score1+(10-loop)/2 { // 如果小明已经赢了
				res = min(res, loop)
			}
			if score1 > score0+(9-loop)/2 { // 如果小红已经赢了
				res = min(res, loop)
			}
		}
	}

	//尽量让小红赢:
	{
		var score0, score1 int
		for loop := 0; loop < 10; loop++ {
			if loop%2 == 0 {
				if s[loop] == '1' {
					score0++
				}
			} else {
				if s[loop] != '0' {
					score1++
				}
			}

			if score0 > score1+(10-loop)/2 { // 如果小明已经赢了
				res = min(res, loop)
			}
			if score1 > score0+(9-loop)/2 { // 如果小红已经赢了
				res = min(res, loop)
			}
		}
	}
	return res + 1
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

注意,上面两个代码块,是尽量让某某赢,但是不能保证某某赢,所以要在最后判断的时候,两种可能性都判断一下才行。