UVa 1635 Irrelevant Elements
题目分析
本题要求我们找出初始数组中的“无关元素”。所谓无关元素,指的是在特定的随机数生成方案中,最终结果不依赖于该元素的初始值。
随机数生成方案
方案步骤如下:
- 初始生成 nnn 个范围在 [0,m−1][0, m-1][0,m−1] 的随机整数 a1,a2,…,ana_1, a_2, \ldots, a_na1,a2,…,an
- 不断将相邻两数相加,得到新数组,长度减 111
- 重复此过程直到只剩一个数
- 对该数取模 mmm 得到最终结果
数学建模
通过观察可以发现,这个不断相邻相加的过程实际上类似于杨辉三角的构建过程。最终结果可以表示为:
S=∑k=1n(n−1k−1)⋅akS = \sum_{k=1}^n \binom{n-1}{k-1} \cdot a_kS=k=1∑n(k−1n−1)⋅ak
最终结果为 S mod mS \bmod mSmodm。
无关元素的判定条件
一个元素 aia_iai 是无关的,当且仅当改变 aia_iai 的值不会影响最终结果 S mod mS \bmod mSmodm。这发生在:
(n−1i−1)≡0(modm)\binom{n-1}{i-1} \equiv 0 \pmod{m}(i−1n−1)≡0(modm)
也就是说,组合数 (n−1i−1)\binom{n-1}{i-1}(i−1n−1) 必须能被 mmm 整除。
问题转化
因此,原问题转化为:对于 i=1,2,…,ni = 1, 2, \ldots, ni=1,2,…,n,判断 (n−1i−1) mod m=0\binom{n-1}{i-1} \bmod m = 0(i−1n−1)modm=0 是否成立。
算法思路
- 质因数分解:将 mmm 分解为质因数的幂次形式 m=p1e1p2e2⋯prerm = p_1^{e_1} p_2^{e_2} \cdots p_r^{e_r}m=p1e1p2e2⋯prer
- 组合数整除性检查:对于每个 iii,检查是否对所有质因子 pjp_jpj 都有:
vpj((n−1i−1))≥ejv_{p_j}\left(\binom{n-1}{i-1}\right) \ge e_jvpj((i−1n−1))≥ej
其中 vp(x)v_p(x)vp(x) 表示 xxx 中质因子 ppp 的幂次 - 收集结果:满足条件的 iii 即为无关元素
复杂度分析
- 质因数分解:O(m)O(\sqrt{m})O(m),在 m≤109m \le 10^9m≤109 时可行
- 组合数检查:O(n×r)O(n \times r)O(n×r),其中 rrr 是 mmm 的质因子个数,通常很小
代码实现
// Irrelevant Elements
// UVa ID: 1635
// Verdict: Accepted
// Submission Date: 2025-10-24
// UVa Run Time: 0.750s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net#include <bits/stdc++.h>using namespace std;// 质因数分解函数
vector<pair<long long, int>> factorize(long long num) {vector<pair<long long, int>> factors;// 从2开始试除for (long long prime = 2; prime * prime <= num; prime++) {if (num % prime == 0) {int exponent = 0;while (num % prime == 0) {num /= prime;exponent++;}factors.emplace_back(prime, exponent);}}// 处理剩余的质因数if (num > 1) {factors.emplace_back(num, 1);}return factors;
}// 计算x!中质因子p的幂次(勒让德公式)
int calculatePrimePower(long long prime, long long num) {int powerCount = 0;while (num >= prime) {powerCount += num / prime;num /= prime;}return powerCount;
}int main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);long long n, m;// 处理多个测试用例while (cin >> n >> m) {// 分解m的质因数auto primeFactors = factorize(m);vector<int> irrelevantIndices;// 检查每个位置i(对应组合数C(n-1, i-1))for (long long index = 0; index < n; index++) {bool isIrrelevant = true;// 检查所有质因子条件for (auto& factor : primeFactors) {long long prime = factor.first;int requiredExponent = factor.second;// 计算组合数中质因子p的幂次:v_p(C(n-1, index))int actualExponent = calculatePrimePower(prime, n - 1) - calculatePrimePower(prime, index) - calculatePrimePower(prime, n - 1 - index);// 如果某个质因子的幂次不足,则该位置不是无关的if (actualExponent < requiredExponent) {isIrrelevant = false;break;}}// 如果满足所有条件,记录该位置if (isIrrelevant) {irrelevantIndices.push_back(index + 1);}}// 输出结果cout << irrelevantIndices.size() << "\n";if (!irrelevantIndices.empty()) {for (size_t j = 0; j < irrelevantIndices.size(); j++) {if (j > 0) cout << " ";cout << irrelevantIndices[j];}cout << "\n";} else {cout << "\n";}}return 0;
}
关键点说明
-
勒让德公式:用于高效计算阶乘中质因子的幂次,公式为:
vp(n!)=⌊np⌋+⌊np2⌋+⌊np3⌋+⋯v_p(n!) = \left\lfloor \frac{n}{p} \right\rfloor + \left\lfloor \frac{n}{p^2} \right\rfloor + \left\lfloor \frac{n}{p^3} \right\rfloor + \cdotsvp(n!)=⌊pn⌋+⌊p2n⌋+⌊p3n⌋+⋯ -
组合数的质因子幂次:
vp((nk))=vp(n!)−vp(k!)−vp((n−k)!)v_p\left(\binom{n}{k}\right) = v_p(n!) - v_p(k!) - v_p((n-k)!)vp((kn))=vp(n!)−vp(k!)−vp((n−k)!) -
整除性判定:m∣(n−1i−1)m \mid \binom{n-1}{i-1}m∣(i−1n−1) 当且仅当对于 mmm 的所有质因子 pep^epe,都有 vp((n−1i−1))≥ev_p\left(\binom{n-1}{i-1}\right) \ge evp((i−1n−1))≥e
该算法通过数论方法高效解决了大数组合数模运算的问题,避免了直接计算可能出现的溢出问题。
