1 条题解
-
0
📝 题目大意
给定 个数,判断能否将它们重新排列,使得任意相邻两个数的乘积都是 的倍数。
💡 解题思路
-
题目分析:相邻两数乘积是 的倍数,意味着这两个数所含的因子 的个数之和至少为 。按模 和模 的余数,可将所有数分为三类:
- 4 的倍数(
cnt[2]):含至少 个因子 ,与任何数相邻都满足条件。 - 2 的倍数但不是 4 的倍数(
cnt[1]):含恰好 个因子 ,只能与同类或 4 的倍数相邻。 - 奇数(
cnt[0]):不含因子 ,只能与 4 的倍数相邻。
- 4 的倍数(
-
算法推导:
-
Case 1:没有"2 的倍数但不是 4 的倍数"(
cnt[1] == 0)
此时只有 4 的倍数和奇数。奇数之间不能相邻,必须用 4 的倍数隔开。 个奇数至少需要 个 4 的倍数作为分隔符,因此条件为cnt[2] + 1 >= cnt[0]。一种可行的构造方式为:4, 奇数, 4, 奇数, ..., 4(奇数结尾)或奇数, 4, 奇数, 4, ..., 奇数(4 结尾)。 -
Case 2:存在"2 的倍数但不是 4 的倍数"(
cnt[1] > 0)
将所有cnt[1]个数聚成一个连续块,块内部任意相邻乘积均为 4 的倍数()。该块的两端只需与 4 的倍数相邻即可。构造方式为:[cnt[1] 块], 4, 奇数, 4, 奇数, ..., 4, 奇数,其中每个奇数前都放置一个 4 的倍数。共需cnt[0]个 4 的倍数(每个奇数前一个),因此条件为cnt[2] >= cnt[0]。
-
-
边界与细节:
- 当 时,没有相邻对,任何排列都满足条件。此时
cnt[1] == 0,cnt[2] + 1 >= cnt[0]恒成立,输出Yes。 - 当所有数都是 2 的倍数但不是 4 的倍数(
cnt[0] = 0, cnt[1] > 0, cnt[2] = 0)时,cnt[2] >= cnt[0]即 成立,输出Yes。确实任意相邻乘积均为 4 的倍数。 - 注意
cnt[2] + 1 >= cnt[0]与cnt[2] >= cnt[0] - 1等价,但直接用cnt[2] + 1 >= cnt[0]可避免cnt[0] = 0时出现负数比较的歧义。
- 当 时,没有相邻对,任何排列都满足条件。此时
⏱️ 复杂度分析
- 时间复杂度:只需遍历 个数一次,统计三类计数,每次操作 ,总复杂度 。
- 空间复杂度:仅需常数大小的
cnt数组(大小为 )和若干临时变量,空间复杂度 。
💻 标准代码 (C++)
#include <bits/stdc++.h> using namespace std; int main(){ int n; cin >> n; // cnt[0]: 奇数个数, cnt[1]: 2的倍数但不是4的倍数, cnt[2]: 4的倍数 vector<int> cnt(3, 0); for(int i = 0; i < n; i++){ int a; cin >> a; if(a % 4 == 0) cnt[2]++; // 4的倍数,含至少2个因子2 else if(a % 2 == 0) cnt[1]++; // 2的倍数但不是4的倍数,含恰好1个因子2 else cnt[0]++; // 奇数,不含因子2 } // 情况1:没有"仅含1个因子2"的数,需用4的倍数隔开所有奇数 if(cnt[1] == 0 && cnt[2] + 1 >= cnt[0]) cout << "Yes" << endl; // 情况2:存在"仅含1个因子2"的数,可将它们聚成一个块,两端靠4的倍数 else if(cnt[2] >= cnt[0]) cout << "Yes" << endl; else cout << "No" << endl; } -
- 1
信息
- ID
- 851
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 1
- 已通过
- 1
- 上传者