比赛链接:Here

1559A. Mocha and Math

题意:

给定一个区间,选择区间内的值执行 & 操作使得区间最大值最小化

观察样例发现:令 x = (1 << 30) - 1 后 \(x\&a_0\& a_1\&...a_{n-1} =\) 答案

证明:

我们假设答案是 x。 在它的二进制表示中,只有在所有 \(a_i\) 的二进制表示中该位为 \(1\) 时,该位才会为 \(1\) 。否则,我们可以使用一个操作使 x 中的该位变为 \(0\) ,这是一个较小的答案。

所以我们可以初始设置 \(x=0\) 或者 \(x = 2^n -1\) 。 然后我们对序列进行迭代,使 \(x=x\&a_i\) ,最终 x 是 anwser。

int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin >> n;
int x = (1 << 30) - 1;
for (int i = 0, a; i < n; ++i) {
cin >> a;
x &= a;
}
cout << x << "\n";
}

1559B.Mocha and Red and Blue

根据贪心思想,找到第一个非 ? 的下标,然后根据下标位置的值去枚举情况即可

int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int _; for (cin >> _; _--;) {
int n; string s;
cin >> n >> s;
for (int i = 0; i < n; ++i)
if (s[i] == '?' and i and s[i - 1] != '?')
s[i] = 'R' ^ 'B' ^ s[i - 1];
if (s.back() == '?') s.back() = 'R';
for (int i = n - 2; i >= 0; --i)
if (s[i] == '?') s[i] = 'R' ^ 'B' ^ s[i + 1];
cout << s << "\n";
}
}

1559C.Mocha and Hiking

路线规律题,

如果 \(a_1 = 1\) 那么路径肯定有 \([(n + 1)\to 1\to2\to...\to n]\)

如果 \(a_n = 0\) 那么路径为 \([1\to2\to...\to n\to (n + 1)]\)

对于其他情况来说:由于 \(a_1=0∧a_n =1\) ,所以肯定存在整数 \(i\) 使得 \(a_i =0∧a_{i + 1}=1\) ,那么路径为 \([1\to 2\to...\to i\to(n + 1)\to (i + 1)\to (i + 2)\to...\to n]\)

具体证明可以参考哈密顿路径

const int N = 1e4 + 10;
int a[N];
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int _; for (cin >> _; _--;) {
int n; cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
int idx = n;
for (int i = 1; i < n; ++i)
if (a[i] == 0 and a[i + 1] == 1) {
idx = i; break;
}
if (a[1] == 1) {
cout << n + 1 << " ";
for (int i = 1; i <= n; ++i) cout << i << " \n"[i == n];
continue;
}
for (int i = 1; i <= idx; ++i)
cout << i << " ";
cout << n + 1 << " ";
for (int i = idx + 1; i <= n; ++i) cout << i << " ";
cout << "\n";
}
}

1559D1.Mocha and Diana (Easy Version)

D1是一个暴力枚举 + 并查集的裸题,D2就懵逼了,不知道怎么维护

两个森林,同时加边后还是森林,求最多加多少边。

并查集,如果两个森林中,i和j两个节点都不在同一个集合中。加边 i--j

比如上图左边1和5不在一个集合,右边1和5也不在一个集合,加边1-5即可

const int N = 2e3 + 10;
int f1[N], f2[N];
int find1(int x) {return f1[x] == x ? x : f1[x] = find1(f1[x]);}
int find2(int x) {return f2[x] == x ? x : f2[x] = find2(f2[x]);}
void merge1(int x, int y) { f1[find1(x)] = find1(y);}
void merge2(int x, int y) { f2[find2(x)] = find2(y);}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m1, m2;
cin >> n >> m1 >> m2;
for (int i = 1; i <= n; ++i) f1[i] = f2[i] = i;
for (int i = 1, u, v; i <= m1; ++i) {
cin >> u >> v;
merge1(u, v);
}
for (int i = 1, u, v; i <= m2; ++i) {
cin >> u >> v;
merge2(u, v);
}
cout << min(n - m1 - 1, n - m2 - 1) << "\n";
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
if (j == i) continue;
if (find1(i) != find1(j) && find2(i) != find2(j)) {
f1[find1(i)] = find1(j);
f2[find2(i)] = find2(j);
cout << i << " " << j << '\n';
}
}
}

1559D2. Mocha and Diana (Hard Version)

参考 B站up主 爱打CF的小赵同学

下面,我们称两个森林为左森林和右森林

如下图

左森林1和2连接

右森林1和4连接

首先,对于左森林和右森林中的某个节点j,同时和节点1不在一棵树上,即左森林中1和j不在一棵树上,右森林中1和j不在一棵树上。

那么就在两个森林中将1和j连接。

左森林和右森林中,节点1和节点3都不在一棵树上,连接1 3这条边,如图

连接之后,还有一类节点可以连接,左森林的i和右森林的j。i和j满足以下条件:

左森林中,1和i在一棵树上,1和j不在一棵树上 ;在右森林中,1和i不在一棵树上,1和j在一棵树上

类似于

节点2在左森林和1相连,节点4在右森林和1相连,则连接2 4 如图

struct DSU {
vector<int> f, siz;
DSU(int n) : f(n), siz(n, 1) {iota(f.begin(), f.end(), 0);}
int find(int x) {return x == f[x] ? x : f[x] = find(f[x]);}
bool same(int x, int y) {return find(x) == find(y);}
bool merge(int x, int y) {
x = find(x), y = find(y);
if (x == y) return false;
siz[x] += siz[y];
f[y] = x;
return true;
}
int size(int x) {return siz[find(x)];}
};
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m1, m2;
cin >> n >> m1 >> m2;
DSU f1(n), f2(n);
for (int i = 0, u, v; i < m1; ++i) {
cin >> u >> v;
--u, --v;
f1.merge(u, v);
}
for (int i = 0, u, v; i < m2; ++i) {
cin >> u >> v;
--u, --v;
f2.merge(u, v);
}
int ans = n - 1 - max(m1, m2);
cout << ans << "\n";
vector<int> v1[n], v2[n];
while (ans > 0) {
for (int i = 0; i < n; ++i) v1[i].clear(), v2[i].clear();
for (int i = 0; i < n; ++i) {
v1[f1.find(i)].push_back(i);
v2[f2.find(i)].push_back(i);
}
int i = 0, j = 0;
while (1) {
while (i < n && f1.find(i) != i) i += 1;
while (j < n && f2.find(j) != j) j += 1;
if (i == n || j == n) break; int a = -1, b = -1, c = -1, d = 0;
for (auto x : v1[i]) {
if (!f2.same(x, j)) a = x;
else c = x;
}
for (auto x : v2[j]) {
if (!f1.same(x, i)) b = x;
else c = x;
} if (a != -1 && b != -1) {
cout << a + 1 << " " << b + 1 << "\n";
f1.merge(a, b);
f2.merge(b, a);
} else {
while (f1.same(d, i) || f2.same(d, j)) d += 1;
cout << c + 1 << " " << d + 1 << "\n";
f1.merge(c, d);
f2.merge(c, d);
}
ans -= 1;
i += 1, j += 1;
}
}
}

1559E. Mocha and Stars

E题在赛时没想到正解,现在学习一下官方的题解

说实话,似乎E题在多校见过?

首先让我们忽略 \(\gcd\) 的限制,令 \(f([l_1,l_2,...,l_n],[r_1,r_2,...,r_n],M)\) 为整数 \((a_1,a_2,..,a_n)\) 的个数满足以下两个条件

  • \(\sum\limits_{i=1}^na_i\le m\)
  • 对于所有的 i ,\(a_i\) 都在 \([l_i,r_i]\) 范围之间

所以我们可以通过前缀和优化背包DP来达到在 \(\mathcal{O}(nM)\) 内完成计算

此时再来考虑 \(\gcd\) 的约束条件,设 \(μ(n)\) 为莫比乌斯函数,\(g(a_1,a_2,…,a_n)\)为 \(1\) ,如果\((a_1,a_2,⋯,a_n)\) 满足我们提到的两个条件(没有 \(\gcd\) 的约束),否则为 \(0\) 。

我们想要的答案是:

\[\begin{array}{ll}
\sum\limits_{a_1=l_1}^{r_1}\sum\limits_{a_2=l_2}^{r_2}...\sum\limits_{a_n=l_n}^{r_n}[\gcd(a_1,a_2,...,a_n)=1]g(a_1,a_2,...,a_n) \\
= \sum\limits_{a_1=l_1}^{r_1}\sum\limits_{a_2=l_2}^{r_2}...\sum\limits_{a_n=l_n}^{r_n}g(a_1,a_2,...,a_n)\sum\limits_{d|\gcd(a_1,a_2,...,a_n)}μ(d)\\
=\sum\limits_{a_1=l_1}^{r_1}\sum\limits_{a_2=l_2}^{r_2}...\sum\limits_{a_n=l_n}^{r_n}g(a_1,a_2,...,a_n)\sum\limits_{d|a_1,d|a_2,..,d|a_n}μ(d)\\
=\sum\limits_{d=1}^Mμ(d)\sum\limits_{a_1=⌈\frac{l_1}d⌉}^{⌊\frac{r_1}d⌋}...\sum\limits_{a_n=⌈\frac{l_n}d⌉}^{⌊\frac{r_n}d⌋} g(a_1d,a_2d,...,a_nd)
\end{array}
\]

因为 \(\sum\limits_{i = 1}^n a_id\le M\) 可以被改写成 \(\sum_{i=1}^na_i\le ⌊\frac Md⌋\) ,等价于

\[\sum\limits_{d=1}^Mμ(d)f(⌈\frac {l_1}d⌉,...,⌈\frac {l_n}d⌉,⌊\frac {r_1}d⌋,...,⌊\frac {r_n}d⌋,⌊\frac Md⌋)
\]

时间复杂度:\(\mathcal{O}(n\sum\limits_{i=1}^M⌊\frac Mi⌋) = \mathcal{O}(nM\ log\ M)\)

#define maxn 100086
const int p = 998244353;
int n, m;
int l[maxn], r[maxn];
int f[maxn], sum[maxn];
int cal(int d) {
int M = m / d;
f[0] = 1;
for (int i = 1; i <= M; i++) f[i] = 0;
for (int i = 1; i <= n; i++) {
int L = (l[i] + d - 1) / d, R = r[i] / d;
if (L > R) return 0;
for (int j = 0; j <= M; j++) sum[j] = (f[j] + (j ? sum[j - 1] : 0)) % p;
for (int j = 0; j <= M; j++) {
f[j] = ((j - L >= 0 ? sum[j - L] : 0) + p - (j - R - 1 >= 0 ? sum[j - R - 1] : 0)) % p;
}
}
int ans = 0;
for (int i = 1; i <= M; i++) ans = (ans + f[i]) % p;
return ans;
}
int prm[maxn], cnt, mu[maxn];
bool tag[maxn];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> l[i] >> r[i];
mu[1] = 1;
for (int i = 2; i <= m; i++) {
if (!tag[i]) prm[++cnt] = i, mu[i] = p - 1;
for (int j = 1; j <= cnt && prm[j] * i <= m; j++) {
tag[i * prm[j]] = true;
if (i % prm[j]) mu[i * prm[j]] = (p - mu[i]) % p;
else break;
}
}
int ans = 0;
for (int i = 1; i <= m; i++) ans = (ans + 1ll * mu[i] * cal(i)) % p;
cout << ans;
}

最后在看H神的代码时发现另外的一个代码思路

const int mod = 998244353;
void add(int &u, int v) {
u += v;
if (u >= mod) u -= mod;
}
void sub(int &u, int v) {
u -= v;
if (u < 0) u += mod;
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m; cin >> n >> m;
vector<int> l(n), r(n);
vector<int> np(m + 1), ans(m + 1), p;
for (int i = 0; i < n; i += 1) cin >> l[i] >> r[i];
for (int i = 2; i <= m; i += 1) {
if (not np[i]) {
p.push_back(i);
for (int j = i * 2; j <= m; j += i) np[j] = 1;
}
}
for (int i = 1; i <= m; i += 1) {
vector<int> L(n), R(n);
int M = m / i, ok = 1;
for (int j = 0; j < n; j += 1) {
L[j] = (l[j] + i - 1) / i;
R[j] = r[j] / i;
if (L[j] > R[j]) ok = 0;
M -= L[j];
R[j] -= L[j];
}
if (not ok or M < 0) continue;
vector<int> dp(M + 1);
dp[0] = 1;
for (int j = 0; j < n; j += 1) {
for (int i = 1; i <= M; i += 1) add(dp[i], dp[i - 1]);
for (int i = M; i >= 0; i -= 1)
if (i > R[j]) sub(dp[i], dp[i - R[j] - 1]);
}
for (int x : dp) add(ans[i], x);
}
for (int x : p)
for (int i = 1; i * x <= m; i += 1)
sub(ans[i], ans[i * x]);
cout << ans[1];
}

Codeforces Round #738 (Div. 2) (A~E)的更多相关文章

  1. Codeforces Round #738 (Div. 2)

    Codeforces Round #738 (Div. 2) 跳转链接 A. Mocha and Math 题目大意 有一个长度为\(n\)的数组 可以进行无数次下面的操作,问操作后数组中的最大值的最 ...

  2. Codeforces Round #738 (Div. 2) D2题解

    D2. Mocha and Diana (Hard Version) 至于D1,由于范围是1000,我们直接枚举所有的边,看看能不能加上去就行,复杂度是\(O(n^2logn)\).至于\(n\)到了 ...

  3. Codeforces Round #366 (Div. 2) ABC

    Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...

  4. Codeforces Round #354 (Div. 2) ABCD

    Codeforces Round #354 (Div. 2) Problems     # Name     A Nicholas and Permutation standard input/out ...

  5. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  6. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  7. Codeforces Round #279 (Div. 2) ABCDE

    Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems     # Name     A Team Olympiad standard input/outpu ...

  8. Codeforces Round #262 (Div. 2) 1003

    Codeforces Round #262 (Div. 2) 1003 C. Present time limit per test 2 seconds memory limit per test 2 ...

  9. Codeforces Round #262 (Div. 2) 1004

    Codeforces Round #262 (Div. 2) 1004 D. Little Victor and Set time limit per test 1 second memory lim ...

  10. Codeforces Round #371 (Div. 1)

    A: 题目大意: 在一个multiset中要求支持3种操作: 1.增加一个数 2.删去一个数 3.给出一个01序列,问multiset中有多少这样的数,把它的十进制表示中的奇数改成1,偶数改成0后和给 ...

随机推荐

  1. LabVIEW基于机器视觉的实验室设备管理系统(3)

    目录 行动计划 创建用户信息数据库 后面板连线 初始化 确认修改 确认id 判断旧密码是否正确 判断两次输入的新密码是否相同 修改用户数据库中的密码 结尾 效果演示 上一期我们完成了欢迎登录和信息查询 ...

  2. 在ASP.NET Core 中使用 .NET Aspire 消息传递组件

    前言 云原生应用程序通常需要可扩展的消息传递解决方案,以提供消息队列.主题和订阅等功能..NET Aspire 组件简化了连接到各种消息传递提供程序(例如 Azure 服务总线)的过程.在本教程中,小 ...

  3. 23C新特性:True Cache的介绍

    我们的文章会在微信公众号"Oracle恢复实录"和博客网站"https://www.cnblogs.com/www-htz-pw/" 同步更新 ,欢迎关注收藏, ...

  4. .NET微信网页开发相关文章教程

    前言 今天我们主要总结一下.NET微信网页开发的相关文章教程. 微信网页开发详细文档可以看微信官方文档:https://developers.weixin.qq.com/doc/offiaccount ...

  5. Curator

  6. 01 MyBatis第一个应用程序

    1.MyBatis是什么? mybatis是一个基于java的持久层框架. 2.什么是持久化 数据由瞬态状态变为持久状态. 3.持久层: 完成持久化工作的代码块. -- DAO层,将数据存到数据库 4 ...

  7. K8s 里如何优雅地使用 /dev/shm 实现容器间共享内存

    目录 1. 从 docker run 的 --shm-size 参数聊起 2. Linux 里的 /dev/shm 3. Docker 对共享内存的支持 4. K8s 里如何设置 /dev/shm 大 ...

  8. matlab 2018b 下载链接

    matlab 2018b 功能强大下载地址为 https://pan.baidu.com/s/1QZO35BtzcIkh_yPYRIGVWg

  9. 华企盾DSC导致wps个人模式无策略组新建的文件仍然加密

    解决方法:右键wps安装目录手动解密即可(原因:wps模板被加密导致)

  10. 【UniApp】-uni-app-动态计算字体大小(苹果计算器)

    前言 本文主要介绍uni-app中动态计算字体大小的方法 原因呢就是在上一篇文章当中我发现输入的内容已经超过了展示区域 于是我就想到了动态计算字体大小的方法,这样就可以保证输入的内容不会超过展示区域 ...