Codeforces Round 1005 (Div. 2)
A. Brogramming Contest
题意:给你一个字符串
考虑该如何操作,如果
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
int ans = 1;
for (int i = 1; i < n; ++ i) {
ans += s[i] != s[i - 1];
}
if (s[0] == '0') {
-- ans;
}
std::cout << ans << "\n";
}
B. Variety is Discouraged
题意:一个数组的价值为数组长度减不同元素个数。给你一个数组,求删去一个区间得到价值最大的且长度最短的子数组。
如果删除一个数,它对价值的贡献是小于等于0的,这个数出现一次,则价值不变,出现多次则价值变小。那么应该删去最长的连续的出现一次的数。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<int> cnt(n + 1);
for (int i = 0; i < n; ++ i) {
++ cnt[a[i]];
}
int ans = 0, ansl = 0, ansr = 0;
for (int i = 0; i < n; ++ i) {
if (cnt[a[i]] == 1) {
int j = i;
while (j + 1 < n && cnt[a[j + 1]] == 1) {
++ j;
}
if (j - i + 1 > ans) {
ans = j - i + 1;
ansl = i, ansr = j;
}
i = j;
}
}
if (ans == 0) {
std::cout << 0 << "\n";
} else {
std::cout << ansl + 1 << " " << ansr + 1 << "\n";
}
}
C. Remove the Ends
题意:给你一个数组
可以取到一个前缀的所有正数和一个后缀的所有负数。且没有一个正数会在负数的后面。那么预处理前缀最大值和后缀最大值,枚举最后删除的位置取最大即可。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<i64> pre(n + 1), suf(n + 2);
for (int i = 0; i < n; ++ i) {
pre[i + 1] = pre[i] + (a[i] > 0 ? a[i] : 0);
}
for (int i = n - 1; i >= 0; -- i) {
suf[i + 1] = suf[i + 2] + (a[i] < 0 ? -a[i] : 0);
}
i64 ans = 0;
for (int i = 1; i <= n; ++ i) {
ans = std::max(ans, pre[i] + suf[i]);
}
std::cout << ans << "\n";
}
D. Eating
题意:给你一个数组,
先把数组翻转,那么变成了从前往后吃,然后记一个前缀异或数组
点击查看代码
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
std::reverse(a.begin() + 1, a.end());
a.push_back(0);
std::vector<int> pre(n + 2);
for (int i = 1; i <= n + 1; ++ i) {
pre[i] = pre[i - 1] ^ a[i];
}
std::vector next(n + 2, std::array<int, 30>{});
std::fill(next[n + 1].begin(), next[n + 1].end(), n + 1);
for (int i = n; i >= 1; -- i) {
next[i] = next[i + 1];
for (int j = 0; j < 30; ++ j) {
if (a[i] >> j & 1) {
next[i][j] = i;
}
}
}
while (q -- ) {
int x;
std::cin >> x;
int l = 0, r = n + 1;
for (int i = 29; i >= 0; -- i) {
if ((x ^ pre[l]) >> i & 1) {
if (r == next[l + 1][i]) {
break;
}
// std::cout << i << " " << l << " " << r << " " << next[l + 1][i] << "\n";
if (next[l + 1][i] < r && (x ^ pre[next[l + 1][i] - 1]) >= a[next[l + 1][i]]) {
l = next[l + 1][i];
r = std::min(r, next[l + 1][i]);
} else {
r = std::min(r, next[l + 1][i]);
break;
}
} else {
r = std::min(r, std::max(l + 1, next[l + 1][i]));
}
// std::cout << l << " " << r << "\n";
}
std::cout << r - 1 << " \n"[!q];
}
}
E. Mycraft Sand Sort
题意:给你一个排列,和一个颜色数组,在一个矩阵中在每一行会生成对应排列数字个数的方块,然后所有方块都往下落。求有多少排列和颜色的方案可以在所有方块下落后和当前这个的每个位置的方块颜色都一样。
赛时手玩了一下,容易发现谁在谁上面都是固定,所以你颜色数组不能变,但同时观察样例发现,相同颜色的行也许可以交换位置,使得最终矩阵不变。然后我赛时也发现了,两行能够交换,只有它们之间的数都小于这两个数才可以。其实这已经观察的差不多了,但我还是不会写。实在太菜了。我赛时主要是不会怎么维护这个东西然后取计数了,比如有一些数可以交换,但可能也有另一部分可以和当前这些数的一部分可以交换,我就是被这里难住了。实际上,利用两个可交换位置的数它们中间的数都小于它们的性质,我们可以按值从小到大做。然后用并查集维护每个可以交换的联通块,那么对于当前这行,它是所有同颜色里目前最小的,然后它可以交换的行我们都维护出来了,那么方案数就之间乘上联通块大小,然后为了后面产生重复贡献,应该把这个联通块的个数减一,这样我们就在一个联通块里,每次选最小的和其他都匹配,然后删去这个最小的,然后到后面次小的和剩下比它大的匹配,不会和之前这个最小的匹配了,就不会用重复。我们每次删除一个数,因为它是最小的数,那么它的两边的联通块如果颜色相同是可以合并的,于是用链表维护。
点击查看代码
struct DSU {
std::vector<int> fa, cnt;
DSU(int _n) {
init(_n);
}
void init(int _n) {
fa.assign(_n, 0);
cnt.assign(_n, 1);
std::iota(fa.begin(), fa.end(), 0);
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool merge(int x, int y) {
x = find(x), y = find(y);
if (x == y) {
return false;
}
fa[y] = x;
cnt[x] += cnt[y];
return true;
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return cnt[find(x)];
}
};
void solve() {
int n;
std::cin >> n;
std::vector<std::pair<int, int>> a(n);
for (int i = 0; i < n; ++ i) {
int x;
std::cin >> x;
-- x;
a[i] = {x, i};
}
std::vector<int> c(n);
for (int i = 0; i < n; ++ i) {
std::cin >> c[i];
}
std::sort(a.begin(), a.end());
std::vector<int> l(n), r(n);
for (int i = 0; i < n; ++ i) {
l[i] = i - 1;
r[i] = i + 1;
}
auto del = [&](int p) -> void {
if (l[p] != -1) {
r[l[p]] = r[p];
}
if (r[p] != n) {
l[r[p]] = l[p];
}
};
DSU dsu(n);
for (int i = 1; i < n; ++ i) {
if (c[i] == c[i - 1]) {
dsu.merge(i, i - 1);
}
}
Z ans = 1;
for (int i = 0; i < n; ++ i) {
int p = a[i].second;
ans *= (Z)dsu.size(p);
dsu.cnt[dsu.find(p)] -= 1;
if (l[p] != -1 && r[p] != n && c[l[p]] == c[r[p]]) {
dsu.merge(l[p], r[p]);
}
del(p);
}
std::cout << ans << "\n";
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具