找到
10
篇与
C++
相关的结果
-
P13100 [FJCPC 2025] 众数 题解 P13100 [FJCPC 2025] 众数 题解 读题 题目数学公式有点多,先简单复述一下题意: 我们有一串数字,比如说 [4, 1, 5, 3]。 “第一个前缀” 就是前面一个数字:[4]。 “第二个前缀” 就是前面两个数字:[4,1]。 “第三个前缀” 就是前三个数字:[4,1,5]。 以此类推... 对于第 $ k $ 个前缀(长度为 $ k $ ),我们可以从里面任意挑选一些位置,至少要选一个。 比如前缀 [4,1,5],可以选 {4},也可以选 {1},也可以选 {5},也可以选 {4,1},甚至可以选 {4,1,5},总共有 $2^k-1$ 种选法。(子集个数公式,这个高一数学会讲,套公式就是快) 然后在选出来的这堆数里,找到最小和最大的那两个数相加 例如子集 {4,1},最小是 1,最大是 4,1+4=5; 例如子集 {5},最小也是最大都是 5,5+5=10; 例如子集 {4,1,5},最小是 1,最大是 5,1+5=6。 我们把所有子集算出来的值放在一起,看哪个数字出现得最多。(这里就不举例了,一个一个算太累了) 特殊情况: 如果出现最多次数的数有好几个,比如“5”和“7”都出现了三次,就选大的那个数“7”作答案。 开始想算法 刚开始想用map做,但因为子集的数量是指数级的($2^{k-1}$),所以如果用map记录来做时间复杂度就是O( $ 2^k $),这里n有 $ 10^6 $ 根本跑不动。(不信可以试一试) 然后就想用数论优化了: 通过样例发现规律:众数的取值仅与当前前缀的最小值、最大值及其出现次数相关。 具体如何推导呢?我们分类讨论吧。这里我们把除了最小值和最大值的其他元素叫做中间元素。 如果存在中间元素,或最小值出现次数不少于 $ 2 $ 包含最小值和最大值的子集,无论是否包含中间元素,其 $ \min $ 必为最小值、$ \max $ 必为最大值,这类子集数量最多。即使存在次数相同的其他和,最小值+最大值也是其中最大的。 所以:众数为最小值+最大值。 若没有中间元素且最小值仅出现 $ 1 $ 次 此时元素只有 $ 1 $ 个最小值和若干最大值,包含最小值和最大值的子集与仅包含最大值的子集数量相同,但 $ 2\times 最大值 $ 更大。 所以:众数为 $ 2\times 最大值 $。 然后我们就可以愉快地写代码啦~ #include <bits/stdc++.h> #define ll long long using namespace std; int main() { ios::sync_with_stdio ( false ); cin.tie ( nullptr ); int T; cin >> T; while ( T-- ) { int n; cin >> n; ll minv = 0, maxv = 0; ll cmin = 0, cmax = 0; for ( int i = 1; i <= n; i++ ) { ll x; cin >> x; if ( i == 1 ) { cout << x * 2 << ' '; minv = maxv = x; cmin = cmax = 1; } else { if ( x == maxv ) { cmax++; } else if ( x > maxv ) { maxv = x; cmax = 1; } else if ( x == minv ) { cmin++; } else if ( x < minv ) { minv = x; cmin = 1; } ll cmid = i - cmin - cmax; if ( cmid > 0 || cmin >= 2 ) { cout << minv + maxv << ' '; } else { cout << maxv * 2 << ' '; } } } cout << endl; } return 0; } -
C++求联通块数量 本文使用了下面五种方法求联通块数量: 并查集 深度优先搜索DFS 广度优先搜索BFS Floyd Kruskal #include<bits/stdc++.h> using namespace std; const int N = 110; const int M = 10010; int n, m; vector<int> g[N]; int ans = 0; // 1.并查集 int pre[N]; int find ( int x ) { return x == pre[x] ? pre[x] : pre[x] = find ( pre[x] ); } void merge ( int x, int y ) { int rx = find ( x ), ry = find ( y ); if ( rx != ry ) { pre[rx] = ry; } } void solveA() { for ( int i = 1; i <= n; i++ ) { pre[i] = i; } for ( int i = 1; i <= m; i++ ) { int u, v; cin >> u >> v; g[u].emplace_back ( v ); g[v].emplace_back ( u ); merge ( u, v ); } for ( int i = 1; i <= n; i++ ) { if ( pre[i] == i ) { ans++; } } cout << ans; } // 2.深搜 int vis[N]; void dfs ( int x ) { for ( auto &u : g[x] ) { if ( vis[u] ) { continue; } vis[u] = true; dfs ( u ); } } void solveB() { for ( int i = 1; i <= m; i++ ) { int u, v; cin >> u >> v; g[u].emplace_back ( v ); g[v].emplace_back ( u ); } for ( int i = 1; i <= n; i++ ) { if ( !vis[i] ) { dfs ( i ); ans++; } } cout << ans; } // 3.广搜 void bfs ( int x ) { queue<int> q; q.emplace ( x ); while ( !q.empty() ) { int u = q.front(); q.pop(); for ( auto &v : g[u] ) { if ( vis[v] ) { continue; } vis[v] = true; q.emplace ( v ); } } } void solveC() { for ( int i = 1; i <= m; i++ ) { int u, v; cin >> u >> v; g[u].emplace_back ( v ); g[v].emplace_back ( u ); } for ( int i = 1; i <= n; i++ ) { if ( !vis[i] ) { bfs ( i ); ans++; } } cout << ans; } // 4.Floyd int adj[N][N]; void solveD() { for ( int i = 1; i <= n; i++ ) { adj[i][i] = 1; } for ( int i = 1; i <= m; i++ ) { int u, v; cin >> u >> v; adj[u][v] = adj[v][u] = 1; } ans = 0; for ( int k = 1; k <= n; k++ ) { for ( int i = 1; i <= n; i++ ) { for ( int j = 1; j <= n; j++ ) { if ( adj[i][k] && adj[k][j] ) { adj[i][j] = 1; } } } } for ( int i = 1; i <= n; i++ ) { if ( !vis[i] ) { ans++; for ( int j = 1; j <= n; j++ ) { if ( adj[i][j] ) { vis[j] = true; } } } } cout << ans; } // 5.Kruskal 最小生成森林 struct Edge { int u, v; } e[M]; void solveE() { for ( int i = 1; i <= n; i++ ) { pre[i] = i; } for ( int i = 1; i <= m; i++ ) { int u, v; cin >> u >> v; e[i] = {u, v}; } ans = n; for ( int i = 1; i <= m; i++ ) { int u = e[i].u, v = e[i].v; int ru = find ( u ), rv = find ( v ); if ( ru != rv ) { merge ( ru, rv ); ans--; } } cout << ans; } // int main() { cin >> n >> m; // solveA(); // solveB(); // solveC(); // solveD(); solveE(); return 0; } -
P1050 [NOIP 2005 普及组] 循环 题目解读 给定一个非常大的整数 $n$ 和一个小整数 $k$,要求计算 $n$ 的正整数次幂 $n^a$ 的 最后 $k$ 位 数字,且这些最后 $k$ 位数字是否会存在某种 循环规律。如果存在这样的循环规律,要求输出 最小的循环长度,如果没有循环规律,则输出 -1。 让我们来看样例 输入:n = 32, k = 2 输出:4 列个表格: $a$$32^a$$32^a \mod 10^2$1323221024243327686841048576765335544323261073741824247343597383686881099511627776769351843720888323210112589990684262424从表格中可以看到: 当 a=1 时,余数为 32。 当 a=2 时,余数为 24。 当 a=3 时,余数为 68。 当 a=4 时,余数为 76。 当 a=5 时,余数再次变为 32,与 a=1 时相同,开始循环。 此后余数序列重复:32 → 24 → 68 → 76 → 32 → ...,循环长度为 4。 知识铺垫 1. 快速幂 问题: 计算 $ n^a \mod 10^k $,如果 $ a $ 很大,直接乘 $ a $ 次会超慢。 快速幂的核心思想:把指数 $ a $ 拆成二进制(就像折纸一样,反复对折),用平方和乘法代替重复乘法。这样能把计算次数从 $ O(a) $ 降到 $ O(\log a) $。 证明 任何指数 $ a $ 可以转换为二进制,这相当于 $ a = 2^{k_1} + 2^{k_2} + \cdots $。 计算 $ n^a $ 时,因为乘法有分配律,我们可以将问题转化为 $ n^1 \times n^2 \times n^4 \times n^8 \times \ldots $。 2. 阶: 在模运算中,幂的结果会循环。阶就是这个循环的最小周期。以样例 $ 32 $ 为例,他的阶就是 $ 4 $。 具体运用 如果知道阶 $d$(循环周期),当 $n^{d} \equiv 1 \pmod{m}$ 时,我们可以构造以下式子: $$ \begin{aligned} n^{d+1} &\equiv n^d \cdot n \equiv 1 \cdot n \equiv n \pmod{m}, \\\\ n^{d+2} &\equiv n^d \cdot n^2 \equiv 1 \cdot n^2 \equiv n^2 \pmod{m}, \\\\ &\quad \vdots \\\\ n^{d+k} &\equiv n^k \pmod{m}. \end{aligned} $$ 由这个式子,我们可以得出 $ n^{a} \equiv n^{a \mod d} \pmod{m} $,将大指数 $ a $ 缩小到 $ a \mod d $。 找阶的方法 条件: $n$ 和模数 $m$ 必须互质,即最大公约数 $\gcd(n, m) = 1$。因为这道题中 $m = 10^k$,所以要求 $n$ 不能被 2 或 5 整除。 欧拉定理: 如果 $\gcd(n, m) = 1$,则 $n^{\phi(m)} \equiv 1 \pmod{m}$。$\phi(m)$ 是小于 $m$ 且与 $m$ 互质的数的个数。 欧拉函数 $\phi(n)$ 的定义: 对于正整数 $n$,欧拉函数 $\phi(n)$ 表示小于或等于 $n$ 的正整数中与 $n$ 互质的数的个数。如果 $n$ 有标准质因数分解: $$ n = p_1^{k_1} p_2^{k_2} \cdots p_m^{k_m} $$那么: $$ \phi(n) = n \left(1 - \frac{1}{p_1}\right)\left(1 - \frac{1}{p_2}\right) \cdots \left(1 - \frac{1}{p_m}\right) $$ 应用于 $m = 10^k$: 首先对 $10^k$ 进行质因数分解: $$ 10^k = (2 \times 5)^k = 2^k \times 5^k. $$因此,$10^k$ 的质因数为 2 和 5。代入欧拉函数公式: $$ \phi(10^k) = 10^k \left(1 - \frac{1}{2}\right)\left(1 - \frac{1}{5}\right). $$所以: $$ \phi(10^k) = 10^k \times \frac{1}{2} \times \frac{4}{5} = 10^k \times \frac{2}{5}. $$进一步化简: $$ \phi(10^k) = \frac{2}{5} \times 10^k = 4 \times 10^{k-1}. $$ 所以对于 $ m = 10^k $,有 $ \phi(10^k) = 10^k \times (1 - \frac{1}{2}) \times (1 - \frac{1}{5}) = 4 \times 10^{k-1} $。 阶 $ d $ 的性质: $ d $ 是最小正整数,使得 $ n^d \equiv 1 \pmod{m} $,且 $ d $ 必须整除 $ \phi(m) $。这里就不证明了,感兴趣可以去自行学习。 找 $ d $ 的步骤: 计算 $ \phi(m) $(如 $ m = 10^k $,则 $ \phi(10^k) = 4 \times 10^{k-1} $。 列出 $ \phi(m) $ 的所有正除数(从小到大)。 测试最小的除数 $ d $ 满足 $ n^d \equiv 1 \pmod{m} $。 这里注意,由于本题的数据范围极大,第 iii 步需要用快速幂算。 For example 找 $ n = 3 $ 在 $ \mod 100 $(即 $ 10^2 $,$ k=2 $ 下的阶。 条件:$ \gcd(3, 100) = 1 $(互质),阶存在。 计算 $ \phi(100) = 100 \times (1 - \frac{1}{2}) \times (1 - \frac{1}{5}) = 40 $。 $ \phi(100) = 40 $ 的除数:1, 2, 4, 5, 8, 10, 20, 40。 测试(用快速幂算 $ 3^d \mod 100 $: $ d = 1 $: $ 3^1 = 3 \not\equiv 1 $ $ d = 2 $: $ 3^2 = 9 \not\equiv 1 $ $ d = 4 $: $ 3^4 = 81 \not\equiv 1 $ $ d = 5 $: $ 3^5 = 243 \equiv 43 \not\equiv 1 $ $ d = 8 $: $ 3^8 = (3^4)^2 = 81^2 = 6561 \equiv 61 \not\equiv 1 $ $ d = 10 $: $ 3^{10} = (3^5)^2 = 243^2 \equiv 43^2 = 1849 \equiv 49 \not\equiv 1 $ $ d = 20 $: $ 3^{20} \equiv (3^{10})^2 \equiv 49^2 = 2401 \equiv 1 \pmod{100} $(成立!) 所以阶 $ d = 20 $。序列每 20 次幂循环一次(如 $ 3^1 \equiv 03 $, $ 3^2 \equiv 09 $, ..., $ 3^{20} \equiv 01 $, $ 3^{21} \equiv 03 $, ...)。 结合快速幂和阶计算 $ n^a \mod 10^k $ 情况 1:$ n $ 和 $ 10^k $ 互质(即 $ n $ 是奇数且不被 5 整除) 这里由于阶存在,我们可以减少指数大小。 步骤: 找阶 $ d $: 计算 $ \phi(10^k) = 4 \times 10^{k-1} $。 找最小 $ d $(整除 $ \phi(10^k) $ 使得 $ n^d \equiv 1 \pmod{10^k} $。 缩小指数:计算 $ r = a \mod d $。 计算结果:因为 $ n^a \equiv n^r \pmod{10^k} $,所以用快速幂计算 $ n^r \mod 10^k $ 就可以算出结果了。 For example 计算 $ 3^{100} \mod 100 $。 $ n = 3 $, $ k = 2 $, $ m = 100 $。 互质:是($ \gcd(3, 100) = 1 $。 找阶:如前,$ d = 20 $。 缩小指数:$ r = 100 \mod 20 = 0 $(当 $ r = 0 $,取 $ n^d \equiv 1 $。 结果:$ 3^{100} \equiv 1 \pmod{100} $。 情况 2:$ n $ 和 $ 10^k $ 不互质(即 $ n $ 含因子 2 或 5) 这里由于欧拉定理要求互质,所以阶可能不存在。 处理思路: 对于大 $ a $,$ n^a \mod 10^k $ 可能最终为 0(如果 $ n $ 含 2 和 5),或进入一个“稳定循环”。但在实践中,常用以下方法: 分离因子:把 $ n $ 写成 $ n = 2^p \times 5^q \times m $,其中 $ m $ 与 10 互质。 计算 $ m^a \mod 10^k $:用情况 1 的方法(阶和快速幂)。 组合结果:结合因子 $ 2^{p a} $ 和 $ 5^{q a} $ 的影响(可能需额外处理)。 代码设计 大整数处理 由于 $n$ 可能非常大,我们使用字符串来表示 $n$,并通过字符串模拟大整数的加法、乘法和除法操作。 求解过程 计算模数:计算 $10^k$(即 $10^k$ 的值)并通过模运算得到结果。 逐步计算次幂:通过逐步计算 $n^a \mod 10^k$,记录每次出现的结果并检查是否出现了重复。 找最小循环长度:如果某个次幂的结果与之前的结果相同,那么就找到了循环,返回循环长度。 完整代码 #include <bits/stdc++.h> using namespace std; // 大整数以10^9为基数的高精度表示 const long long BASE = 1000000000; struct BigInt { vector<long long> a; // 低位块在前 BigInt() {} BigInt(long long v) { *this = v; } BigInt& operator=(long long v) { a.clear(); if (v > 0) { while (v) { a.push_back(v % BASE); v /= BASE; } } return *this; } }; void trim(BigInt &x) { while (!x.a.empty() && x.a.back() == 0) x.a.pop_back(); } bool isZero(const BigInt &x) { return x.a.empty(); } int cmpBig(const BigInt &x, const BigInt &y) { if (x.a.size() != y.a.size()) return x.a.size() < y.a.size() ? -1 : 1; for (int i = (int)x.a.size()-1; i >= 0; --i) { if (x.a[i] != y.a[i]) return x.a[i] < y.a[i] ? -1 : 1; } return 0; } // 大整数加法 BigInt addBig(const BigInt &x, const BigInt &y) { BigInt res; long long carry = 0; size_t n = max(x.a.size(), y.a.size()); res.a.resize(n); for (size_t i = 0; i < n; i++) { long long xi = (i < x.a.size() ? x.a[i] : 0); long long yi = (i < y.a.size() ? y.a[i] : 0); long long s = xi + yi + carry; res.a[i] = s % BASE; carry = s / BASE; } if (carry) res.a.push_back(carry); return res; } // 大整数减法(假设 x >= y) BigInt subBig(const BigInt &x, const BigInt &y) { BigInt res; long long carry = 0; size_t n = x.a.size(); res.a.resize(n); for (size_t i = 0; i < n; i++) { long long xi = x.a[i], yi = (i < y.a.size() ? y.a[i] : 0); long long s = xi - yi - carry; if (s < 0) { s += BASE; carry = 1; } else carry = 0; res.a[i] = s; } trim(res); return res; } // 大整数乘以小整数 BigInt mulSmall(const BigInt &x, long long m) { if (m == 0 || isZero(x)) return BigInt(0); BigInt res; __int128 carry = 0; res.a.resize(x.a.size()); for (size_t i = 0; i < x.a.size(); i++) { __int128 prod = (__int128)x.a[i] * m + carry; res.a[i] = (long long)(prod % BASE); carry = prod / BASE; } while (carry) { res.a.push_back((long long)(carry % BASE)); carry /= BASE; } return res; } // 大整数乘法 BigInt mulBig(const BigInt &x, const BigInt &y) { if (isZero(x) || isZero(y)) return BigInt(0); BigInt res; res.a.assign(x.a.size() + y.a.size(), 0); for (size_t i = 0; i < x.a.size(); i++) { __int128 carry = 0; for (size_t j = 0; j < y.a.size() || carry; j++) { __int128 cur = res.a[i+j] + (__int128)x.a[i] * (j < y.a.size() ? y.a[j] : 0) + carry; res.a[i+j] = (long long)(cur % BASE); carry = cur / BASE; } } trim(res); return res; } // 大整数除以小整数(结果向下取整) BigInt divSmall(const BigInt &x, int m) { BigInt res; res.a.resize(x.a.size()); __int128 carry = 0; for (int i = (int)x.a.size() - 1; i >= 0; i--) { __int128 cur = x.a[i] + carry * BASE; res.a[i] = (long long)(cur / m); carry = cur % m; } trim(res); return res; } // 大整数对小整数取模 int modSmall(const BigInt &x, int m) { __int128 rem = 0; for (int i = (int)x.a.size() - 1; i >= 0; i--) { rem = (rem * BASE + x.a[i]) % m; } return (int)rem; } // 大整数模运算:返回 a mod m BigInt modBig(const BigInt &a, const BigInt &m) { BigInt res = a; if (cmpBig(res, m) < 0) return res; int n = (int)res.a.size(); BigInt cur; cur.a.clear(); for (int i = n - 1; i >= 0; --i) { cur.a.insert(cur.a.begin(), res.a[i]); trim(cur); long long low = 0, high = BASE - 1, best = 0; while (low <= high) { long long mid = (low + high) >> 1; BigInt prod = mulSmall(m, mid); if (cmpBig(prod, cur) <= 0) { best = mid; low = mid + 1; } else { high = mid - 1; } } if (best) { BigInt tmp = mulSmall(m, best); cur = subBig(cur, tmp); } } trim(cur); return cur; } // 大整数欧几里得算法求 GCD BigInt gcdBig(BigInt a, BigInt b) { while (!isZero(b)) { BigInt r = modBig(a, b); a = b; b = r; } return a; } // 大整数快速幂(指数用大数十进制字符串) BigInt pow_mod_str(BigInt base, string exp, const BigInt &mod) { BigInt result(1); while (!(exp.size() == 1 && exp[0] == '0')) { int last = exp.back() - '0'; if (last % 2 == 1) { BigInt mul = mulBig(result, base); result = modBig(mul, mod); } BigInt sq = mulBig(base, base); base = modBig(sq, mod); // exp = exp / 2 int carry = 0; for (int i = 0; i < (int)exp.size(); i++) { int cur = carry * 10 + (exp[i] - '0'); exp[i] = (char)('0' + (cur / 2)); carry = cur % 2; } while (exp.size() > 1 && exp[0] == '0') exp.erase(exp.begin()); } return result; } // 将 BigInt 转为字符串 string toString(const BigInt &x) { if (x.a.empty()) return "0"; string s = to_string(x.a.back()); for (int i = (int)x.a.size()-2; i >= 0; i--) { char buf[16]; sprintf(buf, "%09lld", x.a[i]); s += buf; } return s; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); string n; int k; cin >> n >> k; // 统计 n 中因子 2 和 5 的幂次 int v2 = 0, v5 = 0; // 复制字符串来反复整除 string temp = n; // 计算 v2 while (true) { int carry = 0; string next; next.reserve(temp.size()); for (char c : temp) { int d = c - '0'; int val = carry * 10 + d; next.push_back(char('0' + (val / 2))); carry = val % 2; } if (carry != 0) break; // 不能整除 v2++; // 去除前导零 size_t pos = next.find_first_not_of('0'); if (pos == string::npos) { temp = "0"; break; } temp = next.substr(pos); } // 计算 v5 while (true) { int carry = 0; string next; next.reserve(temp.size()); for (char c : temp) { int d = c - '0'; int val = carry * 10 + d; next.push_back(char('0' + (val / 5))); carry = val % 5; } if (carry != 0) break; v5++; size_t pos = next.find_first_not_of('0'); if (pos == string::npos) { temp = "0"; break; } temp = next.substr(pos); } // 如果存在非平凡因子但小于 k,则无全局循环 if ((v2 > 0 && v2 < k) || (v5 > 0 && v5 < k)) { cout << -1; return 0; } // 如果同时 v2>=k 且 v5>=k,则所有幂的后 k 位都为 0,循环长度为 1 if (v2 >= k && v5 >= k) { cout << 1; return 0; } // 辅助函数:计算 n mod M auto mod_from_string = [&](const BigInt &M)->BigInt { BigInt res(0); for (char c : n) { res = mulSmall(res, 10); BigInt addv(c - '0'); res = addBig(res, addv); if (!isZero(res)) res = modBig(res, M); } return res; }; BigInt one(1), L2(1), L5(1); // 只需处理模 5^k 的情况(v2>=k) if (v2 >= k) { BigInt M5(1); for (int i = 0; i < k; i++) M5 = mulSmall(M5, 5); BigInt nmod = mod_from_string(M5); // 计算模 5^k 的阶:先用 φ(5^k)=4*5^(k-1) 逐步去因子 BigInt phi5(1); phi5 = mulSmall(phi5, 4); for (int i = 1; i < k; i++) phi5 = mulSmall(phi5, 5); L5 = phi5; // 尝试去掉因子 2 while (modSmall(L5, 2) == 0) { BigInt half = divSmall(L5, 2); string exp_str = toString(half); BigInt t = pow_mod_str(nmod, exp_str, M5); if (cmpBig(t, one) == 0) L5 = half; else break; } // 尝试去掉因子 5 while (modSmall(L5, 5) == 0) { BigInt fifth = divSmall(L5, 5); string exp_str = toString(fifth); BigInt t = pow_mod_str(nmod, exp_str, M5); if (cmpBig(t, one) == 0) L5 = fifth; else break; } cout << toString(L5); return 0; } // 只需处理模 2^k 的情况(v5>=k) if (v5 >= k) { BigInt M2(1); for (int i = 0; i < k; i++) M2 = mulSmall(M2, 2); BigInt nmod = mod_from_string(M2); BigInt phi2(1); for (int i = 0; i < k-1; i++) phi2 = mulSmall(phi2, 2); L2 = phi2; while (modSmall(L2, 2) == 0) { BigInt half = divSmall(L2, 2); string exp_str = toString(half); BigInt t = pow_mod_str(nmod, exp_str, M2); if (cmpBig(t, one) == 0) L2 = half; else break; } cout << toString(L2); return 0; } // v2=v5=0,需同时处理模 2^k 和模 5^k { BigInt M5(1); for (int i = 0; i < k; i++) M5 = mulSmall(M5, 5); BigInt nmod = mod_from_string(M5); BigInt phi5(1); phi5 = mulSmall(phi5, 4); for (int i = 1; i < k; i++) phi5 = mulSmall(phi5, 5); L5 = phi5; while (modSmall(L5, 2) == 0) { BigInt half = divSmall(L5, 2); string exp_str = toString(half); BigInt t = pow_mod_str(nmod, exp_str, M5); if (cmpBig(t, one) == 0) L5 = half; else break; } while (modSmall(L5, 5) == 0) { BigInt fifth = divSmall(L5, 5); string exp_str = toString(fifth); BigInt t = pow_mod_str(nmod, exp_str, M5); if (cmpBig(t, one) == 0) L5 = fifth; else break; } } { BigInt M2(1); for (int i = 0; i < k; i++) M2 = mulSmall(M2, 2); BigInt nmod = mod_from_string(M2); BigInt phi2(1); for (int i = 0; i < k-1; i++) phi2 = mulSmall(phi2, 2); L2 = phi2; while (modSmall(L2, 2) == 0) { BigInt half = divSmall(L2, 2); string exp_str = toString(half); BigInt t = pow_mod_str(nmod, exp_str, M2); if (cmpBig(t, one) == 0) L2 = half; else break; } } // 答案是 L = lcm(L2, L5) = (L2 / gcd(L2,L5)) * L5 BigInt g = gcdBig(L2, L5); BigInt quotient; { BigInt x = L2, d = g; int n = (int)x.a.size(); int m = (int)d.a.size(); quotient.a.assign(max(0, n - m + 1), 0); BigInt rem; rem.a.clear(); for (int i = n - 1; i >= 0; --i) { rem.a.insert(rem.a.begin(), x.a[i]); trim(rem); long long low = 0, high = BASE - 1, best = 0; while (low <= high) { long long mid = (low + high) >> 1; BigInt prod = mulSmall(d, mid); if (cmpBig(prod, rem) <= 0) { best = mid; low = mid + 1; } else { high = mid - 1; } } if (best) { BigInt tmp = mulSmall(d, best); rem = subBig(rem, tmp); } if (i - m + 1 >= 0) quotient.a[i - m + 1] = best; } trim(quotient); } BigInt L = mulBig(quotient, L5); cout << toString(L); return 0; } -
【Clion】运行 'test.1.cpp' 时出错 找不到文件 问题详细 今天在Clion调试文件的时候一直提示: 运行 'test.1.cpp' 时出错 找不到文件: C:\Users\24910\Desktop\code\c++\ACGO\test.1.exe查看了目录下生成了test.1,但没有后缀名 查看构建日志: g++.exe C:\Users\24910\Desktop\code\c++\ACGO\test.1.cpp -o test.1所以是因为文件名中带 . 将后面的内容识别为了后缀名,从而导致没有生成exe 解决方法 将带 . 的文件改个名即可。 用于文件很多,我使用Python进行批量重命名: import os root_dir = '.' for foldername, subfolders, filenames in os.walk(root_dir): for filename in filenames: if filename.endswith('.cpp'): name_only = filename[:-4] # 去掉 .cpp if '.' in name_only: # 替换 . 为 空格 new_name_only = name_only.replace('.', ' ') new_filename = new_name_only + '.cpp' old_path = os.path.join(foldername, filename) new_path = os.path.join(foldername, new_filename) # 重命名文件 os.rename(old_path, new_path) print(f'Renamed: {old_path} → {new_path}') -
【洛谷】P2024 [NOI2001] 食物链 题目链接:[P2024 [NOI2001] 食物链](https://www.luogu.com.cn/problem/P2024) 思路 本题可以使用“扩展域并查集”的方法来解决,即把每个节点拆成三种角色(本体、吃的、被吃的)来模拟三种关系。也可以使用“带权并查集”方法,通过设置每个节点到其父节点的相对关系来处理三种状态。 代码 扩展域并查集 #define maxn 50010 #define maxm 100010 #include<bits/stdc++.h> using namespace std; int n, k; int pre[maxn * 3], r[maxn * 3]; int ans = 0; int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); } bool join(int x, int y) { int rx = find(x), ry = find(y); if (rx == ry) { return false; } if (r[rx] < r[ry]) pre[rx] = ry; else { pre[ry] = rx; if (r[rx] == r[ry]) r[rx]++; } return true; } int main() { cin >> n >> k; for (int i = 1; i <= n * 3; i++) pre[i] = i; while (k--) { int opt, x, y; cin >> opt >> x >> y; if (x > n || y > n) { ans++; } else if (opt == 1) { if (find(x) == find(y + n) || find(x) == find(y + n + n)) { ans++; continue; } join(x, y); join(x + n, y + n); join(x + n + n, y + n + n); } else { if (x == y || find(x) == find(y) || find(x) == find(y + n + n)) { ans++; continue; } join(x, y + n); join(x + n, y + n + n); join(x + n + n, y); } } cout << ans << endl; } 带权并查集 #define maxn 50010 #define maxm 100010 #include<bits/stdc++.h> using namespace std; int n, k; int pre[maxn], sz[maxn]; int find(int x) { if (pre[x] != x) { int fa = pre[x]; pre[x] = find(pre[x]); sz[x] = (sz[fa] + sz[x]) % 3; } return pre[x]; } bool join(int x, int y, int w) { int rx = find(x), ry = find(y); if (rx == ry) return (sz[x] - sz[y] + 3) % 3 == w; pre[rx] = ry; sz[rx] = (sz[y] - sz[x] + w + 3) % 3; return true; } int ans = 0; int main() { cin >> n >> k; for (int i = 1; i <= n; i++) pre[i] = i; for (int i = 1; i <= k; i++) { int opt, x, y; cin >> opt >> x >> y; if (x > n || y > n) ans++; else if (opt == 1) { if (!join(x, y, 0)) { ans++; } } else { if (x == y || !join(x, y, 1)) { ans++; } } } cout << ans << endl; return 0; }