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. Unicode 编码 范围

    目录 所有字符 文字部分 ( U+0000 – U+007F) 基本拉丁字符 ( U+0080 – U+00FF) 增补拉丁字符集 1 ( U+0100 – U+017F) 拉丁字符扩展集 A ( U ...

  2. java类的访问修饰符

    1.java中外部类的访问修饰符有如下四种: public,默认,abstract,final // public,默认,abstract,final. public class Test1 {} c ...

  3. Swarm系列7--存储介绍

    存储介绍 1. 存储使用 与docker一样,在使用swarm服务级别的时候可以定义服务的存储需求, docker存储介绍参考: Docker之应用数据管理(volume/bind mount/tmp ...

  4. linux中的内核级防火墙(SELINUX)

    SElinux是基于内核开发出来的一种安全机制,被称之为内核级加强型防火墙,有力的提升了系统的安全性. SElinux的作用分为两方面:1.在服务上面加上标签: 2.在功能上面限制功能 在linux系 ...

  5. Once in a casino CodeForces - 1120B (暴力)

    大意: 给定两个字符串$a,b$, 每个字符为$0-9$, 每次操作将$a$中相邻两位加$1$或减$1$, 操作后每个数仍要为$0-9$, 求最少操作使$a$变成$b$. 先不考虑范围, 判断是否成立 ...

  6. sqlserver时间戳

    SELECT DATEADD(S,1576464113 + 8 * 3600,'1970-01-01 00:00:00') --时间戳转换成普通时间 SELECT DATEDIFF(S,'1970-0 ...

  7. 怎样解决多层this指向全局对象window的问题

    如下所示, 得到的结果里面, 第二个this指向的是window这个全局对象而非f2, 原因就是多层this造成的指向不明引起的. var a = { f1: function(){ console. ...

  8. (九) spring 使用自定义限定符注解

    案例一 定义接口  CD.java package interfacepackage; public interface CD { void play(); } 定义接口 player .java p ...

  9. (一)shiro简介和用户登录demo及角色管理

    一.shiro简介 Apache Shiro是Java的一个安全框架.Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境.Shiro可以帮助我们完成 ...

  10. 三种TCP协议聊天室实现

    一 概述 使用Java的IO实现聊天室 使用Java的NIO实现聊天室 使用Netty实现聊天室 二 IO聊天室 1 服务器 public class IOServer { public static ...