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. gmpy安装使用方法

    gmpy是一种C编码的Python扩展模块,提供对GMP(或MPIR)多精度算术库的访问.gmpy 1.17是1.x系列的最终版本,没有进一步的更新计划.所有进一步的开发都在2.x系列(也称为gmpy ...

  2. (十)SpringBoot之web 应用开发-Servlets, Filters, listeners

    一.需求 Web 开发使用 Controller 基本上可以完成大部分需求,但是我们还可能会用到 Servlet. FilterListene 二.案例 2.1 通过注册 ServletRegistr ...

  3. Java数据结构ArrayList

    Java数据结构ArrayList /** * <html> * <body> * <P> Copyright JasonInternational</p&g ...

  4. Linux 命令实战

    命令登录 ssh  UserName@RemoteIP ssh  seemmo@192.168.0.1 统计文件.目录的数量 统计当前目录下文件数量:ls  -l  |  grep  "^- ...

  5. ztree在onCheck()方法中防止因触发联动关系导致页面多次渲染而卡死的问题

    这几天在项目中遇到了要使用树形选择框, 而且要求比较复杂,具体叙述如下: 首先是有个选择框,左边选择是适用的商品,右边显示已经选择的商品.也就是说,左边每次勾选操作,都要触发一个事件去刷新右边的页面, ...

  6. SQL alchemy

    SQL alchemy介绍 SQL alchemy是orm思想的一个具体实现的产品 orm:对象关系映射思想 Object Relational Mapping 就是将数据库里的资源与面向对象中的类和 ...

  7. TreeMap核心源码实现解析

    TreeMap实现了SotredMap接口,它是有序的集合.而且是一个红黑树结构,每个key-value都作为一个红黑树的节点.如果在调用TreeMap的构造函数时没有指定比较器,则根据key执行自然 ...

  8. 8.读写锁ReadWriteLock

    /*ReadWriteLock 读写锁*/ private ReadWriteLock lock = new ReentrantReadWriteLock(); lock.readLock().loc ...

  9. GC案例

    FGC----jmap -histo:live导致 线上某服务的老年代配置了CMS,但却在gc.log发现连续Full GC的问题.JVM参数配置如下: -XX:+UseCMSInitiatingOc ...

  10. zabbix-通过自动发现添加主机

    当生产环境中需要监控海量的机器的时候,特别是像58.赶集这类同城性质的大网站,或者京东.阿里云这样的造节电商,每次活动.大促都需要添加很多机器来应对海量用户流量,每天都有可能上架新的机器.或者添加新的 ...