Contest Info


Data:2019.6.30
Solved:4/7

Solutions


### A. Stickers and Toys

题意:

有\(A\)物品\(s\)个,\(B\)物品\(t\)个,现在将这些物品装到\(n\)个箱子里,每个箱子只有一下三种情况:

  • 只有一个\(A\)物品
  • 只有一个\(B\)物品
  • 有一个\(A\)物品和一个\(B\)物品

现在问你,至少要取多少个箱子,能够保证你最少有一个\(A\)物品和一个\(B\)物品。

思路:

根据鸽笼原理,显然对于\(A\)物品,至少取\(n - s + 1\)个箱子就可以有一个\(A\)物品。

同理,对于\(B\)物品至少要取\(n - t + 1\)个箱子。

答案就是\(Min(n - s +1, n - t + 1)\)

代码:

#include <bits/stdc++.h>
using namespace std; int main() {
int n, s, t;
int T; scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &n, &s, &t);
int res = max(n - s + 1, n - t + 1);
printf("%d\n", res);
}
return 0;
}

B. Letters Shop

题意:

有一个字符串\(s\),每次询问一个字符串\(t\),问最短的一个\(s\)的前缀使得这个前缀中拥有的字符可以组成字符串\(t\)。

思路一:

可以维护一个字符个数的前缀和,然后二分。

代码一:

#include <bits/stdc++.h>
using namespace std; #define N 200010
int n, m, lens, lent;
char s[N], t[N];
int sum[N][27];
int cnt[27]; bool ok(int x) {
for (int i = 0; i < 26; ++i) {
if (sum[x][i] < cnt[i]) {
return 0;
}
}
return 1;
} int main() {
while (scanf("%d", &n) != EOF) {
memset(sum, 0, sizeof sum);
scanf("%s", s + 1); lens = strlen(s + 1);
for (int i = 1; i <= lens; ++i) {
++sum[i][s[i] - 'a'];
for (int j = 0; j < 26; ++j) {
sum[i][j] += sum[i - 1][j];
}
}
scanf("%d", &m);
while (m--) {
scanf("%s", t + 1); lent = strlen(t + 1);
memset(cnt, 0, sizeof cnt);
for (int i = 1; i <= lent; ++i) {
++cnt[t[i] - 'a'];
}
int l = 1, r = n, res = -1;
while (r - l >= 0) {
int mid = (l + r) >> 1;
if (ok(mid)) {
r = mid - 1;
res = mid;
} else {
l = mid + 1;
}
}
printf("%d\n", res);
}
}
return 0;
}

思路二:

维护\(s\)串中某类字符的第\(i\)个所在位置,显然对于\(t\)串中的每类字符有\(x\)个的话,\(s\)串前缀的长度要大于等于这类字符第\(x\)个所在的位置。

代码二:

#include <bits/stdc++.h>
using namespace std; #define N 200010
int n, m, lens, lent;
char s[N], t[N];
int sum[N][27];
int cnt[27]; bool ok(int x) {
for (int i = 0; i < 26; ++i) {
if (sum[x][i] < cnt[i]) {
return 0;
}
}
return 1;
} int main() {
while (scanf("%d", &n) != EOF) {
memset(sum, 0, sizeof sum);
scanf("%s", s + 1); lens = strlen(s + 1);
for (int i = 1; i <= lens; ++i) {
++sum[i][s[i] - 'a'];
for (int j = 0; j < 26; ++j) {
sum[i][j] += sum[i - 1][j];
}
}
scanf("%d", &m);
while (m--) {
scanf("%s", t + 1); lent = strlen(t + 1);
memset(cnt, 0, sizeof cnt);
for (int i = 1; i <= lent; ++i) {
++cnt[t[i] - 'a'];
}
int l = 1, r = n, res = -1;
while (r - l >= 0) {
int mid = (l + r) >> 1;
if (ok(mid)) {
r = mid - 1;
res = mid;
} else {
l = mid + 1;
}
}
printf("%d\n", res);
}
}
return 0;
}

C. Vasya And Array

题意:

要求构造一个数列\(a_1, \cdots, a_n\),使得满足\(m\)个限制。

限制有两种类型:

  • 1 l r 表示\([l, r]\)范围内的数是非降序的
  • 0 l r 表示\([l, r]\)范围内的数不是非降序的

给出构造结果,或者输出‘NO’表示不存在这样的数列。

思路:

显然非降序的\([l, r]\),我们可以全都赋为\(1\),但是最后一位可以不用赋为\(1\)。

然后将没有赋为\(1\)的地方降序赋值。

再考虑不是非降序的,只要满足这个区间内存在一个\(i\)满足\(a_i > a_{i + 1}\)即可。

只要check一下这些限制的区间内是否有这样一对即可。

否则输出'NO'

因为没考虑这样的对在最后一位的情况被HACK了。

代码:

#include <bits/stdc++.h>
using namespace std; #define N 1010
int n, m;
int s[N];
struct node {
int t, l, r;
node() {}
void scan() {
scanf("%d%d%d", &t, &l, &r);
}
}a[N]; bool ok(int l, int r) {
for (int i = l; i <= r; ++i) {
if (s[i] == 0) {
return 1;
}
}
return 0;
} bool check(node a) {
if (a.t == 1) {
for (int i = a.l + 1; i <= a.r; ++i) {
if (s[i - 1] > s[i]) {
return 0;
}
}
return 1;
} else {
for (int i = a.l + 1; i <= a.r; ++i) {
if (s[i - 1] > s[i]) {
return 1;
}
}
return 0;
}
} void work() {
memset(s, 0, sizeof s);
for (int i = 1; i <= m; ++i) {
if (a[i].t == 1) {
++s[a[i].l];
--s[a[i].r];
}
}
for (int i = 1; i <= n; ++i) s[i] += s[i - 1];
for (int i = 1; i <= n; ++i) {
if (s[i]) s[i] = 1;
}
for (int i = 1; i <= m; ++i) {
if (a[i].t == 0) {
if (!ok(a[i].l, a[i].r)) {
puts("NO");
return;
}
}
}
int cnt = n;
for (int i = 1; i <= n; ++i) {
if (s[i] == 0) {
s[i] = cnt;
--cnt;
}
}
for (int i = 1; i <= m; ++i) {
if (!check(a[i])) {
puts("NO");
return;
}
}
puts("YES");
for (int i = 1; i <= n; ++i) printf("%d%c", s[i], " \n"[i == n]);
} int main() {
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 1; i <= m; ++i) {
a[i].scan();
}
work();
}
return 0;
}

D. Subarray Sorting

题意:

给出两个数组\(a_1, \cdots, a_n\), \(b_1, \cdots, b_n\),可以将\(a\)数组进行不限次数的区间排序,问能够变成\(b\)数组。

思路:

考虑从左往右移动\(a\)中的数使得满足\(a_i = b_i\), 我们发现对于我们需要的\(a_i\),它能移动过来当且仅当它之前不存在比它小的数,

权值线段树维护一下即可。

代码:

#include <bits/stdc++.h>
using namespace std; #define N 300010
int n, a[N], b[N];
int cnt[N], nx[N], f[N]; struct SEG {
int a[N << 2];
void build(int id, int l, int r) {
a[id] = 1e9;
if (l == r) return;
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
}
void update(int id, int l, int r, int pos, int x) {
if (l == r) {
a[id] = x;
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) update(id << 1, l, mid, pos, x);
else update(id << 1 | 1, mid + 1, r, pos, x);
a[id] = min(a[id << 1], a[id << 1 | 1]);
}
int query(int id, int l, int r, int ql, int qr) {
if (ql > qr) return 1e9;
if (l >= ql && r <= qr) {
return a[id];
}
int mid = (l + r) >> 1;
int res = 1e9;
if (ql <= mid) res = min(res, query(id << 1, l, mid, ql, qr));
if (qr > mid) res = min(res, query(id << 1 | 1, mid + 1, r, ql, qr));
return res;
}
}seg; bool work() {
for (int i = 1; i <= n; ++i) {
cnt[i] = 0;
}
for (int i = 1; i <= n; ++i) {
++cnt[a[i]];
--cnt[b[i]];
}
for (int i = 1; i <= n; ++i) {
if (cnt[i] != 0) {
return 0;
}
}
seg.build(1, 1, n);
for (int i = n; i >= 1; --i) {
nx[i] = n + 1;
}
for (int i = n; i >= 1; --i) {
f[i] = nx[a[i]];
nx[a[i]] = i;
}
// for (int i = 1; i <= n; ++i) {
// printf("%d %d\n", i, nx[i]);
// }
for (int i = 1; i <= n; ++i) {
seg.update(1, 1, n, i, nx[i]);
}
for (int i = 1; i <= n; ++i) {
if (seg.query(1, 1, n, 1, b[i] - 1) < nx[b[i]]) return 0;
nx[b[i]] = f[nx[b[i]]];
seg.update(1, 1, n, b[i], nx[b[i]]);
}
return 1;
} int main() {
int T; scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
for (int i = 1; i <= n; ++i) {
scanf("%d", b + i);
}
puts(work() ? "YES" : "NO");
}
return 0;
}

E. Tree Painting

题意:

有一种树上游戏,刚开始每个点为黑点,第一次可以先选择一个点染白,之后每一次都可以选择一个与白点相邻的黑点将其染白,获得的分数为这个黑点所在的由黑点构成的连通块大小。

问在最优策略下获得的最大分数是多少?

思路:

考虑到根固定的话,选择的固定的,即每次从根往下取,而不是隔层取。

树形DP即可。

代码:

#include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 200010
int n;
vector <vector<int>> G;
int fa[N], sze[N];
ll f[N], g[N], res;
void DFS(int u) {
sze[u] = 1;
f[u] = 0;
for (auto v : G[u]) if (v != fa[u]) {
fa[v] = u;
DFS(v);
sze[u] += sze[v];
f[u] += f[v];
}
f[u] += sze[u];
} void DFS2(int u) {
if (u == 1) {
g[u] = 0;
} else {
g[u] = g[fa[u]] + f[fa[u]] - f[u] - sze[u] + n - sze[fa[u]];
res = max(res, f[u] + g[u] - sze[u] + n);
}
for (auto v : G[u]) if (v != fa[u]) {
DFS2(v);
}
} int main() {
while (scanf("%d", &n) != EOF) {
G.clear(); G.resize(n + 1);
for (int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
DFS(1);
res = f[1];
DFS2(1);
printf("%lld\n", res);
}
return 0;
}

Codeforces Educational Codeforces Round 67的更多相关文章

  1. Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings

    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings 题目连接: http://cod ...

  2. Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes

    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes 题目连接: http://code ...

  3. codeforces Educational Codeforces Round 5 A. Comparing Two Long Integers

    题目链接:http://codeforces.com/problemset/problem/616/A 题目意思:顾名思义,就是比较两个长度不超过 1e6 的字符串的大小 模拟即可.提供两个版本,数组 ...

  4. codeforces Educational Codeforces Round 16-E(DP)

    题目链接:http://codeforces.com/contest/710/problem/E 题意:开始文本为空,可以选择话费时间x输入或删除一个字符,也可以选择复制并粘贴一串字符(即长度变为两倍 ...

  5. Codeforces Educational Codeforces Round 15 E - Analysis of Pathes in Functional Graph

    E. Analysis of Pathes in Functional Graph time limit per test 2 seconds memory limit per test 512 me ...

  6. Codeforces Educational Codeforces Round 15 D. Road to Post Office

    D. Road to Post Office time limit per test 1 second memory limit per test 256 megabytes input standa ...

  7. Codeforces Educational Codeforces Round 15 C. Cellular Network

    C. Cellular Network time limit per test 3 seconds memory limit per test 256 megabytes input standard ...

  8. Codeforces Educational Codeforces Round 5 E. Sum of Remainders 数学

    E. Sum of Remainders 题目连接: http://www.codeforces.com/contest/616/problem/E Description The only line ...

  9. Codeforces Educational Codeforces Round 5 D. Longest k-Good Segment 尺取法

    D. Longest k-Good Segment 题目连接: http://www.codeforces.com/contest/616/problem/D Description The arra ...

随机推荐

  1. SAS学习笔记8 循环语句(do函数)

    do-end函数

  2. substr函数索引创建测试

    技术群里小伙伴,沟通说一条经常查询的SQL缓慢,单表SQL一个列作为条件,列是int数值类型,索引类型默认创建. 一.SQL文本substr函数索引创建测试 ,) nm1 ')需求,将上述SQL执行速 ...

  3. 2、Java基础:概念

    1.面向对象和面向过程的区别 面向过程 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机.嵌入式开发.Linux/Unix等一般采用面向过程开发,性能是最重要的因素 ...

  4. VBA算术运算符

    以下是VBA支持算术运算符. 假设变量A=5,变量B=10,那么 - 运算符 描述 示例 + 两个操作数相加 A + B = 15 - 两个操作数相减 A - B = -5 * 两个操作数相乘 A * ...

  5. 用<audio>标签打造一个属于自己的HTML5音乐播放器

    上一章节,我们刚刚讲了<video>标签,今晚,我们讲的是<audio>标签,这两个东东除了表示的内容不一样以外,其他的特性相似的地方真的太多了,属性和用法几乎一样,也就说,如 ...

  6. Java 面向对象(四)继承

    一.继承的概述(Inherited) 1.由来 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可. 其中,多个类可以称为 子类(派生类 ...

  7. 关于一个mvc架构的cms的后台getshell

    都知道,mvc的话 除了根目录还有public目录可以访问,其他的访问都是不行的,因为会默认都是会解析url 然后我们来看今天的猪脚 大概的图片上传还有远程文件加载我黑盒测过了  就是想捞一个快一点的 ...

  8. 从graphql endpoint获取schema文件

    graphql server端有更新,client端需要重新获取schema文件用于创建新的api request,下面简要记录如何从graphql endpoint获取schema文件 You ca ...

  9. Ubuntu安装rpm

    # sudo apt-get install alien # sudo alien xxx.rpm # sudo dpkg -i xxx.deb

  10. zabbix初级进阶

    目录 一.理论概述 zabbix功用 运行条件 缺点 zabbix组件 部署 web安装zabbix 优化 总结 这篇文章主要对zabbix有一个全面且简单的了解 一.理论概述 zabbix功用 检测 ...