Codeforces Round 968 (Div. 2)

news/2024/9/20 18:50:57/文章来源:https://www.cnblogs.com/wenqizhi/p/18380806

良心出题人给了中文题解!!!

A. Turtle and Good Strings

长度为 \(n\) 的字符串至少分成两段,使 \(\forall i < j\) ,第 \(i\) 段的首字符不等于第 \(j\) 段的尾字符

第一个字符一定作为首字符,最后一个字符一定作为尾字符,只要判断这两个字符是否相等即可

相等的话一定无解,不相等一定有解

点击查看代码
#include<bits/stdc++.h>
using namespace std;#define ll long long
#define ull unsigned long longint read()
{int x = 0; bool f = false; char c = getchar();while(c < '0' || c > '9') f |= (c == '-'), c = getchar();while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();return f ? -x : x;
}string s;int main()
{int T = read();while(T--){int len = read();cin >> s;if(s[0] == s[len - 1]) printf("NO\n");else printf("YES\n");}return 0;
}

B. Turtle and Piggy Are Playing a Game 2

假设最终答案为 \(val\)\(\text{Turtle}\) 只需要把小于 \(val\) 的值删除,\(\text{Piggy}\) 只需要把大于 \(val\) 的值删除

等价于对于一个序列,第一步删除最小值,第二步删除最大值,重复操作直至只剩一个数,答案即为第 \(\lfloor \frac{n}{2} \rfloor + 1\) 小的数

点击查看代码
#include<bits/stdc++.h>
using namespace std;#define ll long long
#define ull unsigned long longint read()
{int x = 0; bool f = false; char c = getchar();while(c < '0' || c > '9') f |= (c == '-'), c = getchar();while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();return f ? -x : x;
}const int N = 1e5 + 5;
int a[N];int main()
{int T = read();while(T--){int n = read();for(int i = 1; i <= n; ++i) a[i] = read();sort(a + 1, a + n + 1);printf("%d\n", a[(n >> 1) + 1]);}return 0;
}

C. Turtle and Good Pairs

考场上手动模拟 \((i, j)\) 不做贡献的条件,胡乱推导后得出结论:尽可能使相邻字符不相同

于是用 \(set\) 维护出现次数最多的字符以及它的个数,每次取出次数最多的字符填在第 \(i\) 个位置,并将次数-1

为了使相邻字符不同,先不将第 \(i\) 个字符放回集合(除非下一步没得取了,被迫相邻字符相同),先取出现次数次大的字符

有种摩尔投票统计绝对众数的感觉,当不存在绝对众数时不会出现相邻字符相同的情况

然而猜结论是不行的,需要严谨的数学证明:

image

题解中最小化 $\sum_{i=1}^{m-1} a_i \times a_{i+1} $ 即为尽可能使相邻字符不同

点击查看代码
#include<bits/stdc++.h>
using namespace std;#define ll long long
#define ull unsigned long longint read()
{int x = 0; bool f = false; char c = getchar();while(c < '0' || c > '9') f |= (c == '-'), c = getchar();while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();return f ? -x : x;
}const int N = 2e5 + 5;
int cnt[N];
multiset< pair<int, int> > S;
multiset< pair<int, int> > SS;
string s;
int main()
{int T = read();while(T--){int len = read();cin >> s;for(int i = 0; i <= 25; ++i) cnt[i] = 0;for(int i = 0; i < len; ++i) cnt[s[i] - 'a']++;S.clear(), SS.clear();for(int i = 0; i <= 25; ++i)if(cnt[i]) S.emplace(pair<int, int>(cnt[i], i));for(int i = 1; i <= len; ++i){pair<int, int> now = *prev(S.end());S.erase(now);now.first --;printf("%c", (char)(now.second + 'a'));if(!SS.empty()){S.emplace(*SS.begin());SS.clear();}if(S.empty()) S.emplace(now);else if(now.first ) SS.emplace(now);}printf("\n");}return 0;
}

D1. Turtle and a MEX Problem (Easy Version)

观察到可以使用 \(2\) 次操作同一个序列得到这个序列的第二 \(\text{mex}\)

记第 \(i\) 个序列的 \(\text{mex}\)\(u_i\) ,第二 \(\text{mex}\)\(v_i\)

\(\forall x\)

\[f(x) = \max\{\max_{1\le i \le n} v_i, x\} \]

点击查看代码
#include<bits/stdc++.h>
using namespace std;#define ll long long
#define ull unsigned long longint read()
{int x = 0; bool f = false; char c = getchar();while(c < '0' || c > '9') f |= (c == '-'), c = getchar();while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();return f ? -x : x;
}const int N = 2e5 + 5;
vector<int> a[N];
int mex[N], mmex[N];
int cnt[N];void solve(int id)
{int len = a[id].size();for(int i = 0; i <= len + 1; ++i) cnt[i] = 0;for(int i = 0; i < len; ++i){int x = a[id][i];if(x <= len) cnt[x]++;}mex[id] = 0;for(int i = 0; i <= len + 1; ++i){if(cnt[i] == 0){mex[id] = i;break;}}mmex[id] = 0;for(int i = mex[id] + 1; i <= len + 1; ++i){if(cnt[i] == 0){mmex[id] = i;break;}}
}ll add(int l, int r)
{if(l > r) return 0;return 1ll * (l + r) * (r - l + 1) / 2;
}int main()
{int T = read();while(T--){int n = read(), m = read();for(int i = 1; i <= n; ++i){a[i].clear();int len = read();while(len--){int x = read();a[i].emplace_back(x);}solve(i);}sort(mmex + 1, mmex + n + 1);ll ans = 0, mx = mmex[n];ans = mx * min((mx + 1), 1ll * (m + 1)) + add(mx + 1, m);printf("%lld\n", ans);}   return 0;
}

D2. Turtle and a MEX Problem (Hard Version)

增加了限制:同一个序列 \(i\) 至多操作 \(1\)

考虑有向图:由 \(u_i\)\(v_i\) 连边

一次操作相当于将 \(x\) 变为 \(u_i\) ,并断开 \(u_i\) 的一条出边

\(u_i\) 有超过 \(1\) 条出边时,断开哪条边都可以,也就是哪条边都可以走

\(dp[x]\) 表示当前位于点 \(i\) ,每次选择一条出边能够到达的点编号的最大值

在有向图上倒序 \(dp\)

如何统计答案?

\(\forall x\) 都可以取到 \(\max u_i\)

\(\forall x\) 都可以取到 \(dp[x]\)

\(i\) 的出边个数大于 \(1\) 时,\(\forall x\) 都可以取到 \(dp[i]\)

\(k = \max v_i\) ,小于等于 \(k\) 的枚举,大于 \(k\)\(x\)\(f(x) = x\) 最优

总结

  • 情况复杂时先将所有想到的情况列举下来
点击查看代码
#include<bits/stdc++.h>
using namespace std;#define ll long long
#define ull unsigned long longint read()
{int x = 0; bool f = false; char c = getchar();while(c < '0' || c > '9') f |= (c == '-'), c = getchar();while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();return f ? -x : x;
}const int N = 2e5 + 5;
vector<int> a[N];
int mex[N], mmex[N]; // mmex最大不超过len + 1
int cnt[N];int dp[N], in[N], out[N];
vector<int> e[N];
queue<int> q;void solve(int id)
{int len = a[id].size();for(int i = 0; i <= len + 1; ++i) cnt[i] = 0;for(int i = 0; i < len; ++i){int x = a[id][i];if(x <= len) cnt[x]++;}mex[id] = 0;for(int i = 0; i <= len + 1; ++i){if(cnt[i] == 0){mex[id] = i;break;}}mmex[id] = 0;for(int i = mex[id] + 1; i <= len + 1; ++i){if(cnt[i] == 0){mmex[id] = i;break;}}
}ll add(ll l, ll r)
{if(l > r) return 0;return (l + r) * (r - l + 1) / 2;
}int main()
{int T = read();while(T--){int n = read(), m = read(), mxlen = 0;for(int i = 1; i <= n; ++i){a[i].clear();int len = read();mxlen = max(mxlen, len);while(len--){int x = read();a[i].emplace_back(x);}solve(i);}mxlen++;for(int i = 0; i <= mxlen; ++i){dp[i] = 0, in[i] = 0, out[i] = 0;e[i].clear();}while(!q.empty()) q.pop();for(int i = 1; i <= n; ++i) e[mmex[i]].push_back(mex[i]), ++in[mex[i]], ++out[mex[i]];for(int i = 0; i <= mxlen; ++i)if(in[i] == 0) q.emplace(i);while(!q.empty()){int id = q.front();q.pop();dp[id] = max(dp[id], id);for(int v : e[id]){dp[v] = max(dp[v], dp[id]);--in[v];if(in[v] == 0) q.emplace(v);}}int mx = 0;ll ans = 0;for(int i = 1; i <= n; ++i){mx = max(mx, mex[i]);if(out[mex[i]] >= 2) mx = max(mx, dp[mex[i]]);}ans = add(mx + 1, m);for(int i = 0; i <= min(mx, m); ++i) ans += max(mx, dp[i]);printf("%lld\n", ans);}return 0;
}

E1. Turtle and Inversions (Easy Version)

使所有区间的前缀 \(\max\)\(\max\) 小于所有区间的后缀 \(\min\)\(\min\)

将序列的数分为两种,小数和大数,小数为 \(0\) ,大数为 \(1\) ,将排列转化为 \(01\) 序列

一个排列是有趣排列的充要条件为,它的某个 \(01\) 序列为有趣序列,即对于任意一个区间 \([l, r]\) 所有的 \(0\)\(1\) 前面,且 \(0\)\(1\) 至少都有一个

对于一个有趣序列( \(0\)\(1\) 的位置已经固定),为了使逆序对数最多,可以贪心地将大数 \(1\) 从大到小排列,小数 \(0\) 从大到小排列

一种做法呼之欲出:枚举 \(1\) 的个数,然后将大数小数都从大到小排列,统计逆序对,\(O(n^2)\)

题解给了一种 \(O(n^2)\)\(DP\)

image

考虑 \(O(n)\) 做法:

我们将必须填 \(0\) 的位置称为固定 \(0\) ,必须填 \(1\) 的位置成为固定 \(1\) ,其他位置称为自由点

\(c_i\) 表示位置 \(i\) 之前有几个固定 \(1\) ,设 \(C_i\) 表示位置 \(i\) 之前有几个自由点

假设目前枚举大数 \(1\) 的个数为 \(k\) 个,其中 \(k - m\) 个为自由 \(1\) ,将它们全部放在最靠前的自由点上最优

\(i\) 为固定 \(0\) 时,能和它产生逆序对的 \(1\) 的个数为 \(c_i + \min\{C_i, k - m\}\)

\(i\) 为固定 \(1\) 时,能和它产生逆序对的 \(1\) 的个数为 \(c_i + \min\{C_i, k - m\}\)

\(i\) 为自由点时,不论值为 \(0\) 或者 \(1\) ,能和它产生逆序对的 \(1\) 的个数为 \(c_i + \min\{C_i, k - m\}\)

此时还缺少所有的 \(0\) 相互之间的贡献,即为 \(\frac{(n-k)(n-k-1)}{2}\)

观察 \(c_i + \min\{C_i, k - m\}\)\(c_i\) 不随 \(k\) 变化为定值,单独记录 \(tmp = \sum c_i\)

\(\min\{C_i, k - m\}\)\(k\) 单调不降,将 \(C_i\) 排序后,考虑位置 \(pos\) ,对于 \(i \le pos\)\(C_i < k - m\) ,取 \(\sum C_i\) ,对于 \(i > pos\)\(C_i \ge k - m\)\((k - m) \times (n - pos)\)

对于任意 \(k\) 可以 \(O(1)\) 解决

总结

  • 将排列大小关系转化为 \(01\) 序列
点击查看代码
#include<bits/stdc++.h>
using namespace std;#define ll long long
#define ull unsigned long longint read()
{int x = 0; bool f = false; char c = getchar();while(c < '0' || c > '9') f |= (c == '-'), c = getchar();while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();return f ? -x : x;
}const int N = 5e3 + 5;
int l[N], r[N], c[N], C[N];
int a[N], b[N];void solve()
{int n = read(), m = read();for(int i = 1; i <= n; ++i) c[i] = -1, C[i] = 0;for(int i = 1; i <= m; ++i){l[i] = read(), r[i] = read();c[l[i]] = 0, c[r[i]] = 1;}int L = m, R = n - m;ll tmp = 0;for(int i = 1; i <= n; ++i){if(c[i] == -1) C[i] = 1, c[i] = 0;a[i] = C[i - 1], tmp += c[i - 1];C[i] += C[i - 1], c[i] += c[i - 1]; // 第i个数前面有多少空位,有多少个必选的1}sort(a + 1, a + n + 1);for(int i = 1; i <= n; ++i) b[i] = b[i - 1] + a[i];ll ans = 0, now = 0;int pos = 0;for(int t = L; t <= R; ++t) // t个1{now = 1ll * (n - t) * (n - t - 1) / 2;while(pos < n && a[pos + 1] <= t - m) ++pos;ans = max(ans, now + b[pos] + 1ll * (n - pos) * (t - m));}printf("%lld\n", ans + tmp);
}int main()
{int T = read();while(T--) solve();return 0;
}

E2. Turtle and Inversions (Hard Version)

增加了限制:区间可以相交

考虑两个区间 \([l_i, r_i] , [l_{i + 1}, r_{i + 1}], l_i < l_{i + 1} < r_i\)

对于 \([l_i, l_{i+1}]\) 一定都为 \(0\) ,对于 \([r_i, r_{i+1}]\)\([r_{i+1}, r_i]\) 一定都为 \(1\)

剩余区间为 \([l_{i+1}, min(r_i, r_{i+1})]\) ,即完成了一次区间合并

若干次区间合并后改为区间不交,解法同 \(E1\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;#define ll long long
#define ull unsigned long longint read()
{int x = 0; bool f = false; char c = getchar();while(c < '0' || c > '9') f |= (c == '-'), c = getchar();while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c & 15), c = getchar();return f ? -x : x;
}const int N = 5e3 + 5;
int c[N], C[N];
int a[N], b[N];
pair<int, int> jian[N];bool cmp(pair<int, int> a, pair<int, int> b)
{if(a.first == b.first ) return a.second > b.second ;return a.first < b.first ;
}void solve()
{int n = read(), m = read(), flag = 0;for(int i = 1; i <= n; ++i) c[i] = -1, C[i] = 0;for(int i = 1; i <= m; ++i){jian[i].first = read(), jian[i].second = read();if(!flag && c[jian[i].first ] == 1) flag = 1;if(!flag && c[jian[i].second ] == 0) flag = 1;c[jian[i].first ] = 0, c[jian[i].second ] = 1;}sort(jian + 1, jian + m + 1, cmp);m = unique(jian + 1, jian + m + 1) - (jian + 1);for(int i = 2; i <= m; ++i){if(jian[i].first > jian[i - 1].second ) continue;for(int j = jian[i - 1].first + 1; j < jian[i].first ; ++j){if(c[j] == 1) flag = 1;else c[j] = 0;}for(int j = min(jian[i - 1].second , jian[i].second ) + 1; j < max(jian[i - 1].second , jian[i].second ); ++j){if(c[j] == 0) flag = 1;else c[j] = 1;}jian[i].second = jian[i - 1].second ;}if(flag){ printf("-1\n"); return ; }int L = 0, R = 0;for(int i = 1; i <= n; ++i){if(c[i] == 1) ++L;if(c[i] == 0) ++R; }R = n - R;ll tmp = 0;for(int i = 1; i <= n; ++i){if(c[i] == -1) C[i] = 1, c[i] = 0;a[i] = C[i - 1], tmp += c[i - 1];C[i] += C[i - 1], c[i] += c[i - 1]; // 第i个数前面有多少空位,有多少个必选的1}sort(a + 1, a + n + 1);for(int i = 1; i <= n; ++i) b[i] = b[i - 1] + a[i];ll ans = 0, now = 0;int pos = 0;for(int t = L; t <= R; ++t) // t个1{now = 1ll * (n - t) * (n - t - 1) / 2;while(pos < n && a[pos + 1] <= t - L) ++pos;ans = max(ans, now + b[pos] + 1ll * (n - pos) * (t - L));}printf("%lld\n", ans + tmp);
}int main()
{int T = read();while(T--) solve();return 0;
}

F 先咕着,涉及知识盲区了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/787480.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【日记】这个月花了好多钱(1317 字)

正文这几天都好热。热到人不想动,只想睡觉。今天写文章发现自己有个很显著的特点,就是在有个框架之后,具体细节完全没有预设。我只能像马尔可夫链一样,形成一个比较窄的窗口,接着这个窗口里的情节往下写,否则我就会宕机,写不出来。整个故事情节看起来也就比较散。马尔可…

个人博客导航如何创建更有个性化?

个人博客导航如何创建更有个性化?创建个性化博客导航是一个既实用又能体现个人风格的过程。以下是一些步骤和建议,帮助你完成这一过程:一、确定导航需求和内容明确目的:首先,你需要明确博客导航的主要目的是什么,比如是为了方便读者查找特定内容、展示你的博客结构,还是…

线程基础

生命周期创建线程 class MyThread extends Thread{@Overridepublic void run(){ System.out.println("Hello World"); } }class MyRunnable implements Runnable{@Overridepublic void run() { System.out.println("Hello World"); } }public class Test1 …

网站提示413 Payload Too Large:请求实体过大怎么办

当遇到“413 Payload Too Large”错误时,这意味着客户端发送的请求实体(通常是请求体)超过了服务器允许的最大大小。这种错误通常出现在上传文件或发送大量数据时。 解决方案减小请求体大小检查请求体中的数据量是否过大。 如果是文件上传,考虑减小文件大小或压缩文件。增加…

网站提示500 - 服务器遇到了意外的错误,无法完成请求,可以刷新重试怎么办

当网站提示 500 Internal Server Error 时,这意味着服务器遇到了一个错误,无法完成请求。这种错误通常是由服务器端的问题引起的,可能是由于配置错误、脚本错误、数据库连接问题等。以下是解决 500 Internal Server Error 的一些常见方法: 常见原因服务器配置错误:服务器的…

网站提示405 Method Not Allowed:请求行中指定的请求方法不被允许怎么办

当网站提示 405 Method Not Allowed 时,这意味着服务器理解了您的请求,但是拒绝了请求中指定的 HTTP 方法(如 GET、POST、PUT 等)。这通常是因为服务器被配置为仅接受特定类型的请求方法,而您使用的请求方法不在允许的范围内。以下是解决 405 Method Not Allowed 错误的一…

网站提示404 Not Found:请求的资源未找到怎么办

当网站提示 404 Not Found 时,这意味着服务器无法找到您请求的资源。这种错误通常发生在资源已被删除、移动或从未存在过的情况下。以下是解决 404 Not Found 错误的一些常见方法: 常见原因URL 错误:请求的 URL 不正确或拼写错误。 资源已被删除:请求的资源已被删除。 资源…

网站提示5xx Server Errors(服务器错误状态码)怎么办

当遇到“5xx Server Errors”时,这意味着服务器在处理请求时遇到了错误,这些错误通常与服务器端的问题有关。5xx 系列的状态码包括但不限于:500 Internal Server Error:服务器遇到了一个未曾预料的状况,导致它无法完成对请求的处理。 501 Not Implemented:服务器不支持请…

网站提示451 Unavailable For Legal Reasons:因法律原因不可用怎么办

当遇到“451 Unavailable For Legal Reasons”错误时,这意味着服务器无法提供请求的内容,原因是出于法律原因。这种错误通常出现在内容受到版权保护、涉及敏感信息或其他法律限制的情况下。 解决方案检查内容合法性确认请求的内容是否涉及版权、隐私或其他法律问题。 如果内容…

网站提示503 Service Unavailable:服务器目前无法使用(由于超载或停机维护)怎么办

当遇到“503 Service Unavailable”错误时,这意味着服务器当前因为超载、维护或配置问题而无法处理请求。这种错误通常是因为服务器资源不足或正在进行维护操作。 解决方案刷新页面有时候简单地刷新页面就能解决问题。 服务器可能只是暂时无法响应请求。稍后再试如果服务器正在…

网站提示417 Expectation Failed:期待的请求头字段未满足怎么办

当遇到“417 Expectation Failed”错误时,这意味着服务器无法满足客户端在请求头中设置的 Expect 头字段中的预期。这种错误通常发生在客户端设置了 Expect: 100-continue 头,但服务器没有按照预期进行响应。 解决方案检查 Expect 头确认请求头中的 Expect 字段是否正确。 如…