Codeforces Round #574 (Div. 2)
Contest Info
[Practice Link](https://codeforc.es/contest/1195)
Solved | A | B | C | D1 | D2 | E | F |
---|---|---|---|---|---|---|---|
6/7 | O | O | O | O | O | Ø | - |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A. Drinks Choosing
题意:
有\(n\)个人,每个人喜欢吃第\(k_i\)种糖果,现在商店售卖的糖果是一盒两个的,要买最少数量的盒数,即\(\left\lceil \frac{n}{2} \right\rceil\)盒,并且使得尽量多的人吃上自己喜欢吃的糖果
思路:
将喜欢吃同一种糖果的人放在一起,每次贪心取两个给他们一盒,这样他们的贡献是满的。
剩下的肯定是每种糖果最多只有一个人喜欢吃,那么贡献就是剩余的盒数。
代码:
#include <bits/stdc++.h>
using namespace std;
#define N 1010
int n, k, a[N];
int main() {
while (scanf("%d%d", &n, &k) != EOF) {
memset(a, 0, sizeof a);
for (int i = 1, x; i <= n; ++i) {
scanf("%d", &x);
++a[x];
}
int res = 0;
int num = n / 2 + (n & 1);
for (int i = 1; i <= k; ++i) {
while (a[i] >= 2 && num > 0) {
--num;
a[i] -= 2;
res += 2;
}
}
printf("%d\n", res + num);
}
return 0;
}
B. Sport Mafia
题意:
有两种操作:
- 如果当前盒子里还有糖果,那么可以去掉一个糖果
- 放入盒子一些糖果,糖果的数量是上次放入的数量$ + 1\(
问最终给出操作次数\)n\(以及最终盒子里的糖果数量\)k$,问在操作过程中有多少种操作是第一种操作。
思路:
答案显然是\(i \in [1, n]\),并且满足:
\frac{i * (i + 1)}{2} - (n - i) = k
\end{eqnarray*}
\]
相当于求
\frac{i^2}{2} + \frac{3i}{2} - n - k = 0
\end{eqnarray*}
\]
的方程的根。
显然该二次方程的对称轴在\(-\frac{3}{2}\),所以在\([1, n]\)范围内的根只有一个。
所以直接暴力即可,因为\(i\)的枚举量大概在\(\mathcal{O}(\sqrt{n})\)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n, k;
ll f(int x) {
return 1ll * x * (x + 1) / 2;
}
int main() {
while (scanf("%lld%lld", &n, &k) != EOF) {
for (int i = 1; i <= n; ++i) {
if (f(i) - (n - i) == k) {
printf("%lld\n", n - i);
break;
}
}
}
return 0;
}
C. Basketball Exercise
题意:
有两排人,每排\(n\)个人,现在要求在这两排人中选出一些人,使得他们身高和最高,并且满足以下限制:
- 每一排中被选中的人数不能相邻
- 选择的下标要是递增的
代码:
考虑\(f[i][0/1/2]\)表示到第\(i\)个列位置,选择的是第一排的人,还是第二排的人,还是这一列不选。
转移即可。
思路:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100010
int n;
ll h[N][2], f[N][2];
int main() {
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%lld", &h[i][0]);
}
for (int i = 1; i <= n; ++i) {
scanf("%lld", &h[i][1]);
}
memset(f, 0, sizeof f);
f[1][0] = h[1][0];
f[1][1] = h[1][1];
ll res = 0;
for (int i = 2; i <= n; ++i) {
f[i][0] = h[i][0] + f[i - 1][1];
f[i][1] = h[i][1] + f[i - 1][0];
if (i > 2) {
f[i][0] = max(f[i][0], h[i][0] + max(f[i - 2][0], f[i - 2][1]));
f[i][1] = max(f[i][1], h[i][1] + max(f[i - 2][0], f[i - 2][1]));
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < 2; ++j) {
res = max(res, f[i][j]);
}
}
printf("%lld\n", res);
}
return 0;
}
D1. Submarine in the Rybinsk Sea (easy edition)
题意:
定义拼接函数\(f(a_1a_2 \cdots a_p, b_1b_2 \cdots b_q)\):
\left\{
\begin{array}{cccc}
a_1a_2 \cdots a_{p - q +1}b_1a_{p - q + 2}b_2 \cdots a_{p - 1}b_{q - 1}a_pb_p && p \leq q \\
b_1b_2 \cdots b_{q - p}a_1b_{q - p + 1}a_2 \cdots a_{p - 1}b_{q - 1}a_pb_q && p < q
\end{array}
\right.
\]
再给出一个序列\(a_i\),询问:
\sum\limits_{i = 1}^n\sum\limits_{j = 1}^n f(a_i, a_j) \bmod 998244353
\end{eqnarray*}
\]
在这里保证\(a_i\)的位数相同。
思路:
既然位数相同,那么我们就知道\(f(a_i, ?)\)时\(a_i\)的贡献,以及\(f(?, a_i)\)时\(a_i\)的贡献,分别计算即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100010
const ll p = 998244353;
int n, a[N], len;
int getlen(int x) {
int res = 0;
while (x) {
++res;
x /= 10;
}
return res;
}
ll f(ll x) {
ll tot = 0;
vector <int> vec;
while (x) {
vec.push_back(x % 10);
x /= 10;
}
reverse(vec.begin(), vec.end());
for (auto it : vec) {
tot = tot * 10 + it;
tot = tot * 10 + it;
tot %= p;
}
return tot * n % p;
}
int main() {
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
len = getlen(a[1]);
ll res = 0;
for (int i = 1; i <= n; ++i) {
res += f(a[i]);
res %= p;
}
printf("%lld\n", res);
}
return 0;
}
D2. Submarine in the Rybinsk Sea (hard edition)
题意:
同\(D1\),但是不保证\(a_i\)位数相同。
思路:
位数最多只有\(10\)位,直接暴枚\(a_i\)对应的\(a_j\)的不同位数的贡献即可。
\(10^9\)是一个十位的数字。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100010
const ll p = 998244353;
int n, a[N], num[N];
vector <vector<int>> vec;
int sze[20];
int getlen(int x) {
int res = 0;
while (x) {
++res;
x /= 10;
}
return res;
}
ll f(ll x, int a, int b, int n) {
vector <int> vec, A(22, 0);
while (x) {
vec.push_back(x % 10);
x /= 10;
}
reverse(vec.begin(), vec.end());
int len = a + b;
if (a >= b) {
auto it = vec.begin();
for (int i = 1; i <= a - b + 1; ++i) {
A[i] = *it;
++it;
}
for (int i = a - b + 3; i <= len; i += 2) {
A[i] = *it;
++it;
}
} else {
auto it = vec.begin();
for (int i = b - a + 1; i <= len; i += 2) {
A[i] = *it;
++it;
}
}
// for (int i = 1; i <= len; ++i) printf("%d%c", A[i], " \n"[i == len]);
ll tot = 0;
for (int i = 1; i <= len; ++i) {
tot = tot * 10 + A[i];
tot %= p;
}
return tot * n % p;
}
ll g(ll x, int b, int a, int n) {
vector <int> vec, A(22, 0);
while (x) {
vec.push_back(x % 10);
x /= 10;
}
reverse(vec.begin(), vec.end());
int len = a + b;
if (a >= b) {
auto it = vec.begin();
for (int i = a - b + 2; i <= len; i += 2) {
A[i] = *it;
++it;
}
} else {
auto it = vec.begin();
for (int i = 1; i <= b - a; ++i) {
A[i] = *it;
++it;
}
for (int i = b - a + 2; i <= len; i += 2) {
A[i] = *it;
++it;
}
}
ll tot = 0;
for (int i = 1; i <= len; ++i) {
tot = tot * 10 + A[i];
tot %= p;
}
return tot * n % p;
}
int main() {
while (scanf("%d", &n) != EOF) {
vec.clear();
vec.resize(20);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
vec[getlen(a[i])].push_back(a[i]);
}
for (int i = 1; i <= 10; ++i) sze[i] = (int)vec[i].size();
ll res = 0;
for (int i = 1; i <= 10; ++i) if (sze[i]) {
for (auto it : vec[i]) {
for (int j = 1; j <= 10; ++j) if (sze[j]) {
res += f(it, i, j, sze[j]);
res %= p;
res += g(it, i, j, sze[j]);
res %= p;
}
}
}
printf("%lld\n", res);
}
return 0;
}
E. OpenStreetMap
题意:
求\(n \cdot m\)的矩形中\(a \cdot b\)的所有小矩形的最小值之和。
思路:
二维\(RMQ\)是过不去的。。
考虑复杂度肯定为\(\mathcal{O}(nm)\)。
我们可以竖着枚举矩形右下角,然后再横着枚举。
考虑用\(3000\)个单调队列维护每一行枚举到的最小值,再用一个单调队列维护\(a \cdot b\)矩形内的最小值。
注意加点的时间以及删点的判断。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 3010
int n, m, a, b;
ll g[N * N], x, y, z;
int B[N][N], l[N], r[N], que[N], L, R;
int get(int x, int y) {
return (x - 1) * m + y - 1;
}
int main() {
while (scanf("%d%d%d%d", &n, &m, &a, &b) != EOF) {
L = 1, R = 0;
for (int i = 1; i <= n; ++i) l[i] = 1, r[i] = 0;
scanf("%lld%lld%lld%lld", g, &x, &y, &z);
for (int i = 1; i <= n * m; ++i) g[i] = (g[i - 1] * x + y) % z;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j < b; ++j) {
while (l[i] <= r[i] && g[get(i, j)] < g[B[i][r[i]]]) {
--r[i];
}
B[i][++r[i]] = get(i, j);
}
}
ll res = 0;
for (int i = 1; i <= a; ++i) {
while (L <= R && g[B[i][l[i]]] < g[que[R]]) --R;
que[++R] = B[i][l[i]];
}
for (int j = b; j <= m; ++j) {
for (int i = 1; i <= n; ++i) {
while (l[i] <= r[i] && abs(B[i][l[i]] - get(i, j)) >= b) ++l[i];
while (l[i] <= r[i] && g[get(i, j)] < g[B[i][r[i]]]) --r[i];
B[i][++r[i]] = get(i, j);
}
L = 1, R = 0;
for (int i = 1; i < a; ++i) {
while (L <= R && g[B[i][l[i]]] < g[que[R]]) --R;
que[++R] = B[i][l[i]];
}
for (int i = a; i <= n; ++i) {
while (L <= R && abs(que[L] - get(i, j)) >= (a - 1) * m + b) ++L;
while (L <= R && g[B[i][l[i]]] < g[que[R]]) --R;
que[++R] = B[i][l[i]];
res += g[que[L]];
}
}
printf("%lld\n", res);
}
return 0;
}
Codeforces Round #574 (Div. 2)的更多相关文章
- Codeforces Round #574 (Div. 2)——C. Basketball Exercise(简单DP)
题目传送门 题意: 输入n,给出两组均为 n个数字的数组a和b,轮流从a和b数组中取出一个数字,要求严格按照当前所选数字的数组下标比上一个所选数字的数组下标更大,计算能够取出的数字加起来的总和最大能为 ...
- Codeforces Round #574 (Div. 2)题解
比赛链接 传送门 A题 题意 \(n\)个人每个人都有自己喜欢喝的\(vechorka\)口味,现在给你\(\lceil n/2\rceil\)箱\(vechorka\),每箱有两瓶,问最多能有多少个 ...
- Codeforces Round #574 (Div. 2)补题
A. Drinks Choosing 统计每种酒有多少人偏爱他们. ki 为每种酒的偏爱人数. 输出ans = (n + 1)/2 > Σki / 2 ? (n + 1)/2 - Σki / ...
- Codeforces Round #574 (Div. 2) A~E Solution
A. Drinks Choosing 有 $n$ 个人,每个人各有一种最喜欢的饮料,但是买饮料的时候只能同一种的两个两个买(两个一对) 学校只打算卖 $\left \lceil \frac{n}{2} ...
- Codeforces Round #574 (Div. 2) E.OpenStreetMap
题目链接 题目的意思就是给你一个矩阵你要求给定子矩阵的最小值的和 单调队列扫两边即可 #include <bits/stdc++.h> #define ll long long #defi ...
- Codeforces Round #574 (Div. 2) E. OpenStreetMap 【单调队列】
一.题目 OpenStreetMap 二.分析 对于二维空间找区间最小值,那么一维的很多好用的都无法用了,这里可以用单调队列进行查找. 先固定一个坐标,然后进行一维的单调队列操作,维护一个区间长度为$ ...
- Codeforces Round #574 (Div. 2) D2. Submarine in the Rybinsk Sea (hard edition) 【计算贡献】
一.题目 D2. Submarine in the Rybinsk Sea (hard edition) 二.分析 相比于简单版本,它的复杂地方在于对于不同长度,可能对每个点的贡献可能是有差异的. 但 ...
- Codeforces Round #574 (Div. 2) D1. Submarine in the Rybinsk Sea (easy edition) 【计算贡献】
一.题目 D1. Submarine in the Rybinsk Sea (easy edition) 二.分析 简单版本的话,因为给定的a的长度都是定的,那么我们就无需去考虑其他的,只用计算ai的 ...
- 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 ...
随机推荐
- Android--圆角背景style
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http: ...
- vue cli3 项目优化
vue-cli3 Prefetch (官网内容) <link rel="prefetch"> 是一种 resource hint,用来告诉浏览器在页面加载完成后,利用空 ...
- 使用postman mock server
需要写一个小的Java程序,用来调用云平台的接口 由于云平台的接口程序还没有写好,只能用模拟的方式先行开发代码, 用了post来模拟接口程序. 需要模拟的接口如下: ■请求地址 /openapi/ip ...
- Informix从一个表更新多选数据到另一个表
功能如题, Informix从一个表更新多选数据到另一个表 例如, 要更新tab01的几个字段数据, 这些数据来自tab02, tab01和tab02之间通过id关联 参考语句: update tab ...
- js 单引号和双引号相互替换的实现方法
1.双引号替换成单引号 var domo = JSON.stringify(address).replace(/\"/g,"'"); var a = {a:1,b:2}; ...
- 14 Windows编程——SetWindowLong
使用默认窗口处理函数,源码 #include<Windows.h> #include<Windowsx.h> LRESULT CALLBACK WindProc(HWND hw ...
- Nginx上传和超时时间限制 (php上传限制) - 运维笔记
现象说明:在服务器上部署了一套后台环境,使用的是nginx反向代理tomcat架构,在后台里上传一个70M的视频文件,上传到一半就失效了! 原因:nginx配置里限制了上传文件的大小 client_m ...
- 读取xml时,报错:xml.etree.ElementTree.ParseError: no element found: line 20, column 9
读取xml时,出现报错:xml.etree.ElementTree.ParseError: no element found: line 20, column 9 原因是xml文件格式有问题,可以检查 ...
- WCF服务代理类-学习
类:ServiceDescriptionImporter Class 公开一种为 XML Web services 生成客户端代理类的方法. 地址:https://docs.microsoft.com ...
- jade变量声明和数据传递
声明一个变量 - var course = 'jade'; 取得一个变量 #{course} 大括号里面写入变量命,前面加个#号就可以取得变量 在括号里面可以进行诸多都运行操作,比如大小写 #{cou ...