【刷题日记】蓝桥村的真相(推理与规律)
P11003 [蓝桥杯 2024 省 Python B] 蓝桥村的真相
题目链接
题目描述
在风景如画的蓝桥村,\(n\) 名村民围坐在一张古老的圆桌旁,参与一场思想
的较量。这些村民,每一位都有着鲜明的身份:要么是誉满乡野的诚实者,要么是无可救药的说谎者。
当会议的钟声敲响,一场关于真理与谬误的辩论随之展开。每位村民轮流发言,编号为 \(i\) 的村民提出了这样的断言:坐在他之后的两位村民——也就是
编号 \(i + 1\) 和 \(i + 2\)(注意,编号是环形的,所以如果 \(i\) 是最后一个,则 \(i + 1\) 是
第一个,以此类推)之中,一个说的是真话,而另一个说的是假话。
在所有摇曳不定的陈述中,有多少真言隐藏在谎言的面纱之后?
请你探索每一种可能的真假排列组合,并计算在所有可能的真假组合中,
说谎者的总数。
输入格式
输入的第一行包含一个整数 \(T\),表示每次输入包含 \(T\) 组数据。
接下来依次描述 \(T\) 组数据。
每个数据一行包含一个整数 \(n\),表示村落的人数。
输出格式
输出 \(T\) 行,每行包含一个整数,依次表示每组数据的答案。
输入输出样例 #1
输入 #1
2
3
3
输出 #1
6
6
说明/提示
对于 \(10\%\) 的评测用例,\(T = 1,3 \le n \le 10\)。
对于 \(40\%\) 的评测用例,\(1 \le T \le 10^2,3 \le n \le 3 \times10^3\)。
对于所有评测用例,\(1 \le T \le 10^5,3 \le n \le 10^{18}\)。
样例解释
在样例中,可能的组合有「假,假,假」「真,真,假」「真,假,真」「假,
真,真」,说谎者的总数为 \(3 + 1 + 1 + 1 = 6\)。
题解
思路
当所有人说假话
首先,当所有人都是无可救药的说谎者时:每个人说自己之后有人说真话,这显然是说谎!所以,所有人都在说谎,这是肯定没错的。
如果有人说真话
那有人说真话的情况下,不产生冲突的情况有哪些呢?
记录说真话的人为\(1\),说谎话的人为\(0\)。
假设第一个人说真话,那么第二个人和第三个人中就有一真一假。
如果第二个人说真话
如果第二个人说真话,则目前的串为\(110\)。
如果存在第四个人,则根据\(2\)号所言,\(3\)和\(4\)中有一个说真话的人,\(3\)说假话,那么\(4\)一定说真话,得到\(1101\),这时显然不能结束(如果一共只有\(4\)个人,推理结束,则\(4\)号说\(1\)号和\(2\)号有一个人说假话,则\(4\)号说错了!),一定需要存在第五个人。
根据\(3\)号所言,\(4\)号和\(5\)号并不是“一真一假”,即“都真”或“都假”,已知\(4\)号说真话,则\(5\)号说真话,得到\(11011\),这时仍然不能结束(如果一共只有\(5\)个人,推理结束,则\(5\)号说\(1\)号和\(2\)号有一个人说假话,则\(5\)号说错了!),一定需要存在第六个人。
根据\(4\)号所言得知\(6\)一定说假话,这时推理可以结束,得到\(110110\),\(6\)号说\(1\)号和\(2\)号并非“一真一假”,即“都真”或“都假”,不矛盾,这是个合理的结束。也可以继续推理下去。
这时初见端倪:如果前三个人为\(110\),则第四个到第六个人也为\(110\),且有且只有这种递推可行,并且中间不能断掉(不能只有\(4\)或\(5\)个人)。同样,第七到第九个人也为\(110\),不能中间断掉(不能只有\(7\)或\(8\)个人)。
如果第二个人说假话
如果第二个人说假话,则目前的串为\(101\)。
如果存在第四个人,则根据\(2\)号所言,\(4\)应该说真话,得到\(1011\),此时不能结束(\(3\)号说真话,但\(4\)和\(1\)都说真话,与\(3\)号所言矛盾),递推……直到推理出\(101101\)才能结束。也可以继续推理下去。
发现规律
前三个人的组合可以是\(011\),\(101\),\(110\),共三种组合方式,每种都可以无限延伸下去,前提是人数必须为\(3\)的倍数。当然,所有人都说假话,也是可行的。
总结规律
如果人数是\(3\)的倍数,在以上三种组合方式中,根据\(n mod 3\)(\(n\)对\(3\)取模)为\(0/1/2\),总会出现一次,则这三种方案一共出现了\(n\)个说假话的人。加上所有人都说假话时的\(n\)个,答案为\(2n\)。
如果人数不是\(3\)的倍数,则只有“都说假话”一种可能性,所以答案为\(n\)。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
i64 n, t;
int main() {
	cin >> t;
	while (t--) {
		cin >> n;
		if (n % 3 == 0) {
			cout << 2 * n << '\n';
			continue;
		}
		cout << n << '\n';
	}
	return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号