【刷题日记】蓝桥村的真相(推理与规律)

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\)

\[ ans = \begin{cases} 2n & n \equiv 0 (mod 3) \\ n & n \not\equiv 0 (mod 3) \end {cases}\]

代码

#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;
}
posted @ 2025-08-15 15:48  Alkaid16  阅读(12)  评论(0)    收藏  举报