1.29.codeforces div2 C,D 题解,如何高效掌握?

摘要:C. Restricted Sorting 贪心 题目描述 给你一个长度为 (n) 的数组 (a)。对于一个整数 (k),当且仅当可以通过执行以下操作任意次(包括零次)将 (a) 按非降序排序时,我们称它为“贪心的”(pig
C. Restricted Sorting 贪心 题目描述 给你一个长度为 \(n\) 的数组 \(a\)。对于一个整数 \(k\),当且仅当可以通过执行以下操作任意次(包括零次)将 \(a\) 按非降序排序时,我们称它为“贪心的”(piggy): 首先,选择两个下标 \(i\) 和 \(j\)(\(1 \leq i < j \leq n\)),使得 \(|a_i - a_j| \geq k\); 然后,交换 \(a_i\) 和 \(a_j\)。 你需要找出最大的“贪心”整数 \(k\)。如果这样的整数不存在,输出 \(-1\)。 输入格式 每个测试包含多个测试用例。第一行包含测试用例的数量 \(t\)(\(1 \leq t \leq 10^4\))。接下来是每个测试用例的描述。 每个测试用例的第一行包含一个整数 \(n\)(\(1 \leq n \leq 2 \cdot 10^5\))——数组 \(a\) 的长度。 第二行包含 \(n\) 个整数 \(a_1, a_2, \dots, a_n\)(\(1 \leq a_i \leq 10^9\))——数组 \(a\) 的元素。 保证所有测试用例的 \(n\) 之和不超过 \(2 \cdot 10^5\)。 输出格式 对于每个测试用例,输出一个整数——最大的“贪心”整数 \(k\)。 如果这样的整数不存在,输出 \(-1\)。 思路 原数组为\(a[N]\),排序后为\(b[N]\) 如果\(a_{i}\)能够移动,那么必然存在一个\(a_{j}\)使得\(|a_{i}-a_{j}|\geq k\),那么至少要有\(a_{i}-a_{min}\geq k\)或者\(a_{max}-a_{i}\geq k\) 若满足了上述两个条件之一,那么说明\(a_{i}\)一定可以与最大值或者最小值交换位置 那么所有满足上述条件的点所构成的位置集合\(S_{pos}\),这些位置上的点可以通过与最大值最小值交换位置实现任意位置交换 对于\(a_{i}\neq b_{i}\)的点,必须满足\(a_{i}\)可移动且\(b_{i}\)可移动,才能在最终交换到正确位置上 因此,对于\(a_{i}\neq b_{i}\)的位置,可以计算出一个符合条件的最大\(k\): \[k=min(max(a[i]-mi,ma-a[i]),max(b[i]-mi,ma-b[i])) \] 对所有的\(k\)取最小值即可 代码 #include<bits/stdc++.h> using namespace std; #define ll long long #define int ll #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define ull unsigned long long void solve() { int n;cin >> n; vector<int>a(n + 1); vector<int>b(n + 1); vector<int>k(n + 1, 1e18); int ma = 0, mi = 1e18; rep(i, 1, n)cin >> a[i], b[i] = a[i], ma = max(ma, a[i]), mi = min(mi, a[i]); sort(b.begin() + 1, b.end()); bool dif = 0;int ans = 1e18; rep(i, 1, n) { if (a[i] != b[i]) { int k = min(max(a[i] - mi, ma - a[i]), max(b[i] - mi, ma - b[i])); dif = 1; ans = min(ans, k); } } if (!dif) { cout << -1 << '\n';return; } cout << ans << '\n'; } signed main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--)solve(); } D. Shortest Statement Ever 数位dp #dp 题目描述 给定两个非负整数 \(x\), \(y\)。请找出两个非负整数 \(p\) 和 \(q\),使得 \(p \& q = 0\),且 \(|x - p| + |y - q|\) 最小。这里,\(\&\) 表示按位与操作。 输入格式 每个测试包含多个测试用例。第一行包含测试用例的数量 \(t\)(\(1 \leq t \leq 10^4\))。接下来是每个测试用例的描述。 每个测试用例仅有一行,包含两个非负整数 \(x\) 和 \(y\)(\(0 \leq x, y < 2^{30}\))。 输出格式 对于每个测试用例,输出你找到的两个非负整数 \(p\) 和 \(q\)。如果有多个满足条件的 \(p\) 和 \(q\) 对,你可以输出其中任意一对。 可以证明,在问题的约束下,任意有效解都满足 \(\max(p, q) < 2^{31}\)。 思路 由于数字小于\(2^{30}\),可以考虑使用数位dp从高位开始遍历到低位,选出最优的\(p,q\) 状态设计与转移: \(dp[pos][rp][rq]\) \(pbit,qbit=\{ 0,0 \},\{ 0,1 \},\{ 1,0 \}\) \(rp=0\)表示当前\(p\)已经遍历的高位与\(x\)都相同 如果\(pbit<xbit\),\(newpr=1,cost+=(1\ll pos)\) 如果\(pbit>xbit\),\(newpr=2,cost+=(1\ll pos)\) 如果\(pbit=xbit\),\(newpr=0\) \(rp=1\)表示当前\(p<x\) \(cost+=(xbit-pbit)\ll pos\) \(rp=2\)表示当前\(p>x\) \(cost+=(pbit-xbit)\ll pos\) \(rq\)的状态设计同理 为了在\(dp\)结束后能够通过回溯过程找回\(p,q\),创建一个选择数组\(ch[pos][rp][rq]\),表示在最优的选择情况下,\(pbit,qbit\)在\(\{ 0,0 \},\{ 0,1 \},\{ 1,0 \}\)中选择了哪个 代码 #include<bits/stdc++.h> using namespace std; #define ll long long #define int ll #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define ull unsigned long long const int inf = 1e18; int mem[32][3][3], ch[32][3][3]; bool vis[32][3][3]; int Ax[32], Ay[32]; int pp[3] = { 0,1,0 }; int qq[3] = { 0,0,1 }; int dfs(int pos, int rp, int rq) { if (pos < 0)return 0; if (vis[pos][rp][rq])return mem[pos][rp][rq]; int ans = inf; rep(i, 0, 2) { int pbit = pp[i], qbit = qq[i]; int xbit = Ax[pos], ybit = Ay[pos]; int cost = 0; int nrp = rp, nrq = rq; if (rp == 0) { if (pbit < xbit)nrp = 1, cost += (1ll << pos); else if (pbit > xbit)nrp = 2, cost += (1ll << pos); } else if (rp == 1)cost += ((ll)(xbit - pbit) << pos); else cost += ((ll)(pbit - xbit) << pos); if (rq == 0) { if (qbit < ybit)nrq = 1, cost += (1ll << pos); else if (qbit > ybit)nrq = 2, cost += (1ll << pos); } else if (rq == 1)cost += ((ll)(ybit - qbit) << pos); else cost += ((ll)(qbit - ybit) << pos); int res = cost + dfs(pos - 1, nrp, nrq); if (res < ans) { ans = res; ch[pos][rp][rq] = i; } } vis[pos][rp][rq] = 1; return mem[pos][rp][rq] = ans; } void solve() { int x, y;cin >> x >> y; rep(pos, 0, 30) { Ax[pos] = (x >> pos) & 1; Ay[pos] = (y >> pos) & 1; } memset(vis, 0, sizeof(vis)); dfs(30, 0, 0); int p = 0, q = 0; int crp = 0, crq = 0; per(pos, 30, 0) { int idx = ch[pos][crp][crq]; int pbit = pp[idx], qbit = qq[idx]; if (pbit)p |= (1ll << pos); if (qbit)q |= (1ll << pos); int xbit = Ax[pos], ybit = Ay[pos]; if (crp == 0) { if (pbit < xbit)crp = 1; else if (pbit > xbit)crp = 2; } if (crq == 0) { if (qbit < ybit)crq = 1; else if (qbit > ybit)crq = 2; } } cout << p << " " << q << '\n'; } signed main() { ios::sync_with_stdio(0); cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--)solve(); }