Codeforces Round #822 (Div. 2) A-F
A
题解
知识点:贪心。
注意到任意三根木棍的相等最优解是最长减最小,因此从小到大排序,三个三个取,取最小值。
时间复杂度 \(O(n\log n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[307];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
sort(a + 1, a + n + 1);
ll ans = a[3] - a[1];
for (int i = 3;i <= n;i++) {
ans = min(ans, a[i] - a[i - 2]);
}
cout << ans << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
B
题解
知识点:构造。
注意到第 \(i\) 行的房间最多明亮值为 \(i\) ,又发现只需要两侧房间安排火把已经满足一行最大值,因此直接两侧房间 \(1\) 其他都是 \(0\) 。
时间复杂度 \(O(n^2)\)
空间复杂度 \(O(1)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= i;j++) {
if (j == 1 || j == i) cout << 1 << ' ';
else cout << 0 << ' ';
}
cout << '\n';
}
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
C
题解
知识点:贪心,数学。
从小到大,把每一个要删除的数当作 \(k\) 枚举倍数,如果是要删除的数花费一次 \(k\) 删掉,如果已经删过则无视,如果不是要删除的数则停止换下一个 \(k\) 。
时间复杂度 \(O(n\log n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int vis[1000007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) {
char c;
cin >> c;
vis[i] = c == '1';
}
ll sum = 0;
for (int i = 1;i <= n;i++) {
if (vis[i] == 1) continue;
for (int j = i;j <= n;j += i) {
if (vis[j] == 1) break;
if (vis[j] == 0) {
vis[j] = 2;
sum += i;
}
}
}
cout << sum << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
D
题解
知识点:贪心,枚举。
先选择一个方向直走,比如先走左侧,走到不能再走为止,把尽头的生命值 \(lnw\) 记录下。
此时考虑回头,但显然在左侧尽头回头不是一定最优的,应该在走左侧过程中生命值和最大处回头才是最优的,因为这样在走右侧时可以走最多的路,因此在走左侧的过程中也要记录左侧的生命和最大值 \(lmx\) 。
同理从 \(lmx\) 回头走右侧时,也是走到尽头记录右侧最大生命值 \(rmx\) 和尽头生命值 \(rnw\) 。此时从 \(rmx\) 回头走左侧,应该直接从上一次的左侧尽头位置 \(lnw\) 继续走。
如此来回往复,直到两侧不能继续走或者到达两端为止。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[200007];
bool solve() {
int n, k;
cin >> n >> k;
for (int i = 1;i <= n;i++) cin >> a[i];
int i = k - 1, j = k + 1;
ll lmx = 0, lnw = 0, rmx = 0, rnw = 0;
while (1 <= i && j <= n) {
bool ok = false;
while (1 <= i) {
if (a[k] + lnw + rmx + a[i] < 0) break;
ok = true;
lnw += a[i--];
lmx = max(lmx, lnw);
}
while (j <= n) {
if (a[k] + lmx + rnw + a[j] < 0) break;
ok = true;
rnw += a[j++];
rmx = max(rmx, rnw);
}
if (!ok) break;
}
if (i == 0 || j == n + 1) cout << "YES" << '\n';
else cout << "NO" << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
E
题解
知识点:构造,数学。
注意到,
& & a_{i_1,j_1} + a_{i_2,j_2} \not \equiv a_{i_1,j_2} + a_{i_2,j_1} \pmod n\\
&\Leftrightarrow & a_{i_2,j_2} - a_{i_2,j_1} \not \equiv a_{i_1,j_2} - a_{i_1,j_1} \pmod n
\end{aligned}
\]
猜测一行元素具有线性关系,设 \(i_1\) 行线性系数为 \(k_1\) ,\(i_2\) 行线性系数为 \(k_2\) ,于是有:
&\Leftrightarrow & (j_2-j_1)\cdot k_2 \not \equiv (j_2-j_1)\cdot k_1 \pmod n
\end{aligned}
\]
根据定理:当 \(k > 0\) 时,若 \(kx \equiv ky \pmod n\) ,则 \(x \equiv y\pmod {\frac{n}{gcd(k,n)}}\) 。
于是有:
&\Leftrightarrow & k_2 \not \equiv k_1 \pmod n
\end{aligned}
\]
因此,只要每行之间的线性系数在 \(\mod n\) 意义下不同余,且在 \((i,i)\) 处经过 \(b_i\) 即可。
显然,\(i \in [1,n]\) 时即能保证互不同余,可以当作系数,因此有公式 \(b_{i,j} = (i \cdot (j-i) + b_i) \mod n\) 。
时间复杂度 \(O(n^2)\)
空间复杂度 \(O(n^2)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[357][357], b[357];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> b[i];
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
a[i][j] = ((i * (j - i) + b[i]) % n + n) % n;
}
}
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
cout << a[i][j] << ' ';
}
cout << '\n';
}
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
//cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
F
题解
知识点:记忆化搜索,线性dp,数学,位运算。
先是一个结论:定义函数 \(parity(a)\) 表示 \(a\) 二进制位 \(1\) 的个数的奇偶性(奇数返回 \(1\) ,偶数返回 \(0\)),那么 \(S_i = parity(i)\) 。
证明非常简单:
- 由于 \(S\) 的生成方法是每次都从原来的一份取反得到 \(S'\) 放到 \(S\) 末尾,所以第 \(k(k\geq 1)\) 次扩展后 \(S\) 的编号一定是 \([0,2^{k-1}]\) 。
- 对于第 \(k+1\) 次新生成的 \(S'\) 中的每一位编号 \(i'\) ,满足 \(i’ = i + 2^k\) ,因为编号 \(i\) 的第 \(k\) 位之前一定是 \(0\),所以这次变换实际上是将编号 \(i\) 的第 \(k\) 位变为 \(1\) 作为编号 \(i'\)。
- 显然,所有数字都是从编号 \(0\) 开始数次变换得到的,每次变换都会将编号的一位 \(0\) 变为 \(1\) ,因此我们记录二进制 \(1\) 的数量就能得知这个编号从 \(0\) 变换了多少次。
- \(S_0 = 0\) ,所以编号 \(i\) 有偶数个 \(1\) 就是变了偶数次,故 \(S_i=0\) ,否则 \(S_i = 1\) 。即 \(S_i = parity(i)\) 。
有了这个结论,我们就可以对问题进行量化。记原问题答案为 \(f(n,m)\) ,有 \(f(n,m) = \sum_{i = 0}^{m-1} [parity(i) \neq parity(n+i)]\) 。
当 \(m = 0\) 时,显然有 \(f(n,0) = 0\) 。
当 \(m\) 为奇数时,先对末尾判断再对 \(m-1\) 讨论(偶数讨论方便一点),有 \(f(n,m) = f(n,m-1) + [parity(i) \neq parity(n+i)]\) 。
当 \(m\) 为偶数时:
\(n\) 为偶数,有如下关系:
\[\begin{aligned}
&& &parity(2k) \neq parity(n+2k) \\
&\Leftrightarrow& &parity(2k+1) \neq parity(n+2k+1)\\
\end{aligned}
\]因为偶数末尾总是 \(0\) ,加 \(1\) 不会影响其余的二进制位,所以 \(1\) 的数量明确加 \(1\) ,奇偶性一定同时改变。
\[\begin{aligned}
&& &parity(2k) \neq parity(n+2k) \\
&\Leftrightarrow& &parity(k) \neq parity(\frac{n}{2}+k)
\end{aligned}
\]因为偶数末尾总是 \(0\) ,删去这个 \(0\) 后,数字奇偶性不变。
那么有如下公式:
\[\begin{aligned}
f(n,m) &= \sum_{i = 0}^{m-1} [parity(i) \neq parity(n+i)]\\
&= 2\sum_{k = 0}^{\frac{m}{2}-1} [parity(2k) \neq parity(n+2k)]\\
&= 2\sum_{k = 0}^{\frac{m}{2}-1} [parity(k) \neq parity(\frac{n}{2}+k)]\\
&= 2f(\frac{n}{2},\frac{m}{2})
\end{aligned}
\]\(n\) 为奇数,有如下关系:
\[\begin{aligned}
&& &parity(2k) \neq parity(n+2k) \\
&\Leftrightarrow& &parity(2k) = parity(n+2k-1)\\
&\Leftrightarrow& &parity(k) = parity(\frac{n-1}{2}+k)\\
\end{aligned}
\]以及,
\[\begin{aligned}
&& &parity(2k+1) \neq parity(n+2k+1) \\
&\Leftrightarrow& &parity(2k) = parity(n+2k+1)\\
&\Leftrightarrow& &parity(k) = parity(\frac{n+1}{2}+k)\\
\end{aligned}
\]证明同上。
\[\begin{aligned}
f(n,m) &= \sum_{i = 0}^{m-1} [parity(i) \neq parity(n+i)]\\
&= \sum_{k = 0}^{\frac{m}{2}-1} ([parity(2k) = parity(n+2k-1)] + [parity(2k) = parity(n+2k+1)])\\
&= \sum_{k = 0}^{\frac{m}{2}-1} ([parity(k) = parity(\frac{n-1}{2}+k)] + [parity(k) = parity(\frac{n+1}{2}+k)])\\
&= m - f(\frac{n-1}{2},\frac{m}{2}) - f(\frac{n+1}{2},\frac{m}{2})
\end{aligned}
\]
至此,我们就可以通过记忆化搜索进行求解了。
时间复杂度 \(O(\log n \log m)\)
空间复杂度 \(O(\log n \log m)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool check(ll a, ll b) {
return __builtin_parityll(a) != __builtin_parityll(b);
}
map<pair<ll, ll>, ll> mp;
ll f(ll n, ll m) {
if (m == 0) return 0;
if (mp.count({ n,m })) return mp[{n, m}];
if (m & 1) return mp[{n, m}] = f(n, m - 1) + check(m - 1, n + m - 1);
if (n & 1) return mp[{n, m}] = m - f(n / 2, m / 2) - f((n + 1) / 2, m / 2);
else return mp[{n, m}] = 2 * f(n / 2, m / 2);
}
bool solve() {
ll n, m;
cin >> n >> m;
cout << f(n, m) << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
Codeforces Round #822 (Div. 2) A-F的更多相关文章
- Codeforces Round #573 (Div. 1) 差F
Codeforces Round #573 (Div. 1) E 题意:二维平面上有 n 个点,你可以放至多 m 条直线使得 (0,0) 与每个点的连线至少与一条直线相交.求原点与所有直线的距离最小值 ...
- Codeforces Round #541 (Div. 2) (A~F)
目录 Codeforces 1131 A.Sea Battle B.Draw! C.Birthday D.Gourmet choice(拓扑排序) E.String Multiplication(思路 ...
- Codeforces Round #532 (Div. 2):F. Ivan and Burgers(贪心+异或基)
F. Ivan and Burgers 题目链接:https://codeforces.com/contest/1100/problem/F 题意: 给出n个数,然后有多个询问,每次回答询问所给出的区 ...
- Codeforces Round #600 (Div. 2)E F
题:https://codeforces.com/contest/1253/problem/E 题意:给定n个信号源,俩个参数x和s,x代表这个信号源的位置,s代表这个信号源的波及长度,即这个信号源可 ...
- Codeforces Round #346 (Div. 2) E F
因为很久没有个人认真做题了 昨天晚上开了场虚拟cf来锻炼个人手速 选的是第一次做cf的场 那时候7出3还被hack...之后也没补题 这次做的时候顺便回忆了一下以前比赛的时候是怎么想的 发现经验还是很 ...
- Codeforces Round #322 (Div. 2) E F
E. Kojiro and Furrari 题意说的是 在一条直线上 有n个加油站, 每加一单位体积的汽油 可以走1km 然后每个加油站只有一种类型的汽油,汽油的种类有3种 求从起点出发到达终点要求使 ...
- Codeforces Round #506 (Div. 3) 1029 F. Multicolored Markers
CF-1029F 题意: a,b个小正方形构造一个矩形,大小为(a+b),并且要求其中要么a个小正方形是矩形,要么b个小正方形是矩形. 思路: 之前在想要分a,b是否为奇数讨论,后来发现根本不需要.只 ...
- Codeforces Round #485 (Div. 2) F. AND Graph
Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...
- Codeforces Round #486 (Div. 3) F. Rain and Umbrellas
Codeforces Round #486 (Div. 3) F. Rain and Umbrellas 题目连接: http://codeforces.com/group/T0ITBvoeEx/co ...
随机推荐
- Github隐藏使用技巧(超详解)
目录 github使用说明 查看别人的主页和项目 上传自己的项目 使用git下载github上的文件 使用git实现代码管理 使用git恢复被修改的文件 更多关于git使用小技巧 github使用说明 ...
- TFrecord写入与读取
Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializi ...
- 学会使用MySQL的Explain执行计划,SQL性能调优从此不再困难
上篇文章讲了MySQL架构体系,了解到MySQL Server端的优化器可以生成Explain执行计划,而执行计划可以帮助我们分析SQL语句性能瓶颈,优化SQL查询逻辑,今天就一块学习Explain执 ...
- BACnet MS/TP转MQTT网关金鸽BL103
BACnet MS/TP转MQTT网关金鸽BL103BL103是一款BACnet路由器,实现 BACnet MS/TP 总线和以太网 BACnetIP 之间通信路由功能,同时也是一款Modbus RT ...
- Linux Shell 自动交互功能
需求背景: 近日,在安装某软件过程,发现在安装过程需要输入一些信息才能继续下一步操作,在机器数量较少情况下,我们可以单台登录上去完成安装操作,但当机器数量超过一定时,如果再手动登录操作,就会产生大 ...
- 「POJ 3666」Making the Grade 题解(两种做法)
0前言 感谢yxy童鞋的dp及暴力做法! 1 算法标签 优先队列.dp动态规划+滚动数组优化 2 题目难度 提高/提高+ CF rating:2300 3 题面 「POJ 3666」Making th ...
- 原生js也可以自定义组件
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的web应用中使用它们. 它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元 ...
- java-数组排序之冒泡排序(经典排序)
public class BubbleSort { public static void main(String[] args) { /*冒泡排序不一定是用时最短的 * 1)声明整型数组arr,包含1 ...
- kafka详解(一)--kafka是什么及怎么用
kafka是什么 在回答这个问题之前,我们需要先了解另一个东西--event streaming. 什么是event streaming 我觉得,event streaming 是一个动态的概念,它描 ...
- Flume 组件安装配置
下载和解压 Flume 实验环境可能需要回至第四,五,六章(hadoop和hive),否则后面传输数据可能报错(猜测)! 可 以 从 官 网 下 载 Flume 组 件 安 装 包 , 下 载 地 址 ...