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. Scratch—点亮生日蜡烛

    过生日是小朋友们创作Scratch作品经常会用到的素材,今天介绍使用一些基础技能来点亮生日蜡烛的实现方法. 1.角色设计只有三种:生日蛋糕.未点燃的蜡烛.已点燃的蜡烛. 2.未点燃的蜡烛:在程序启动时 ...

  2. java中的自动装箱和拆箱

    一.什么是自动装箱和拆箱: 我们知道java为8种基本类型分别提供了对应的包装类型,在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行: Integer i=new I ...

  3. (六)Hibernate的增删改查操作(3)

    一.在Hibernate中使用原生SQL语句 sql语句面向的是数据库,所以sql语句中对应的不再是bean了,比如sql="select * from user"   在hql中 ...

  4. (四)springmvc之获取servlet原生对象

    一.使用DI注入的方式 <a href="<%=request.getContextPath()%>/servletObj_1">DI注入的方式</a ...

  5. leetcode --165--php

    class Solution { /** * @param String $version1 * @param String $version2 * @return Integer */ functi ...

  6. WebSocket协议探究(二)

    一 复习和目标 1 复习 协议概述: WebSocket内置消息定界并且全双工通信 WebSocket使用HTTP进行协议协商,协商成功使用TCP连接进行传输数据 WebScoket数据格式支持二进制 ...

  7. Junit 学习1 junit的简单使用

    package junit; import java.sql.Connection; import java.sql.SQLException; import org.junit.Test; impo ...

  8. R语言学习笔记:glue包实现变量传参

    glue包介绍 glue包可用于自定义变量,然后通过传参的方式,对字符串部分内容进行自适应修改. 例如:可将日期赋值为:date = as.Date("2019-12-05"),然 ...

  9. cygwin_exception::open_stackdumpfile: Dumping stack trace to HttpServer.exe.stackdump错误

    本来,我在Windows下使用Cygwin编译运行c程序,在执行*.exe时报出如题错误,我在Linux环境下使用gcc编译运行,则正常. 所以,当你无法解决上述问题时,换系统吧!

  10. 高射炮打蚊子,杀鸡用绝世好剑:在SAP Kyma上运行UI5应用

    国人在表述"大材小用"这个场景时,总喜欢用一些实物来类比,比如:高射炮打蚊子. 英国QF 3.7英寸(94mm)高射炮,战斗全重超过9.3吨,全长近5米,最大射程约18公里,最大射 ...