在 \(\text{Div. 2/3}\) 混了一个多月后,四个号终于都上紫了,也没用理由不打 \(\text{Div. 1}\) 了。这是我人生中的第一场 \(\text{Div .1}\) ,之前也没用刻意的刷过题。在赛场上 \(\text{A}\) 在 WA 了 \(3\) 次后终于过了,然后 \(35 \text{min}\) 的时候过了 \(\text{B}\),想了一个小时 \(\text{C}\) 未果,耻辱下线。事后上了 \(60\) 分,大概是安慰吧......

A. Dreamoon Likes Coloring

比较显然地想到贪心,让左端点从左到右的顺序放线段,每次最少给上次的颜色留出一个位置即可。

然后比较坑的是,这题你放的左端点必须保证右端点 \(\le n\),所以贪心地考虑就是让每条线段尽量往左放,但是你又不知道往左放后面会不会不够。所以记录一个 \(d = n - m\)。初始设定每个颜色包含的块时 \(1\),\(d\) 维护的就是当前还需要扩展的块数。然后逆向思维,从右往左考虑,尽量让左端点往左边放即可,但是不能超过 \(d\),否则把别的颜色本该有的地方给占领了。

几个无解的判断:

  • \(\sum l < n\) 肯定有空白

  • \(l_m > n - (m - 1)\) 最后一个覆盖了太多,导致容不下 \(m\) 个颜色

  • 放的过程中发现右端点势必 \(> n\)

还有一些细节,具体看代码

时间复杂度 \(O(n)\)

#include <iostream>
#include <cstdio> using namespace std; const int N = 100005; int n, m, l[N], ans[N]; typedef long long LL; LL s = 0; int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) scanf("%d", l + i), s += l[i];
if (s < n) {
puts("-1");
return 0;
}
if (l[m] > n - (m - 1)) {
puts("-1");
return 0;
} int j = n - l[m] + 1;
int d = (j - 1) - (m - 1);
ans[m] = j;
for (int i = m - 1; i; i--) {
j -= min(d + 1, l[i]) ;
d -= min(d + 1, l[i]) - 1;
if (j + l[i] - 1 > n) {
puts("-1");
return 0;
}
ans[i] = j;
}
for (int i = 1; i <= m; i++) printf("%d ", ans[i]);
return 0;
}

B. Dreamoon Likes Sequences

既然要保证异或和、值本身都上升的序列。那么不妨从二进制的角度去考虑:

  • 要让值上升,意味着 \(a_{2}\) 在二进制下最高的 \(1\) 大于等于 \(a_{1}\) 的位置,否则 \(a_{i - 1}\) 就大了
  • 异或和上升,意味着 \(a_2\) 在二进制下最高的 \(1\) 必须大于 \(a_1\) 的位置,否则异或和就把最高的那处一消掉了,就不能保证上升了。

然后通过数学归纳法,我们能知道 \(a_i\) 和 \(b_i\) 二进制意义下最高的 \(1\) 位置是一样的,否则被消掉了肯定不能保证异或和上升。

所以若 \(a_{i + 1}\) 能接上 \(a_i\),当且仅当 \(a_{i + 1}\) 二进制下最高的 \(1\) 比 \(a_i\) 大。

由于不涉及序列长度以及具体数值,只关心最后一个数二进制下最高的 \(1\) 的位置,那么这样设计 \(\text{DP}\) 状态:

  • 设 \(f_i\) 表示一段序列,最后一个数在二进制下最高的 \(1\) 在第 \(i\) 位的方案数。

考虑状态转移,\(f_j (j > i) \gets f_i * \text{w(j)}\)。\(\text{w(j)}\) 表示在二进制下最高位是 \(1\),且不超过 \(d\) 的数字的数量,这个很好搞,下界就是 \(2^j\),上界就是 \(\min(2^{j+1}-1, d)\)。

注意初始化,第一个元素可以为 \([1, d]\) 的任意值。

时间复杂度 \(O(T\log^2 10^9)\)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; typedef long long LL; const int S = 31; int d, P, f[S]; int main() {
int T; scanf("%d", &T);
while (T--) {
memset(f, 0, sizeof f);
scanf("%d%d", &d, &P);
for (int i = 0; i < S; i++) {
if ((1 << i) > d) continue;
int c = min((LL)d, (1ll << (i + 1)) - 1) - (1 << i) + 1;
f[i] = c;
}
for (int i = 0; i < S; i++) {
if (f[i] == 0) continue;
for (int j = i + 1; j < S; j++) {
if ((1 << j) > d) continue;
int c = min((LL)d, (1ll << (j + 1)) - 1) - (1 << j) + 1;
f[j] = (f[j] + (LL)c * f[i]) % P;
}
}
int ans = 0;
for (int i = 0; i < S; i++) (ans += f[i]) %= P;
printf("%d\n", ans);
}
return 0;
}

C. Drazil Likes Heap

考虑每一次的删数操作,实际上是将一个叶子节点的位置去除了,我们要保证堆的结构仍然为满二叉树,删除总和最大的一些数。我们可以预处理出来删除每个节点,最终会去除的叶子节点的位置的高度,设这个东西为 \(maxDep_i\)。

我们发现,删除一个数是否合法的条件为:\(maxDep_i > g\)。否则会打破深度限制。

然后贪心策略是:从小到大的顺序依次考虑每一层,能删则删,循环直到不能删为止。为啥这样是对的呢?首先我们的策略应该是:尽可能删合法的大的,因为假设你不删大的,那一定还得删另外一个数,来消除本应该这个大的数消除的叶子位置,这样顶替的肯定不优,所以能删则删。

还有个性质,就是说不同子树之间删除互不影响,这个比较显然,因为自己删除只会改变自己的子树。所以根据堆的性质,我们只需要从小到大考虑每一层能不能删即可。可以理解为当考虑删除当前位置的节点时,权重更大的能消除这个位置的(就是当前节点的祖先)已经考虑过了,所以这种枚举方式是正确的。

代码实现起来,就是模拟一个堆,然后删除的过程中不要忘了维护 \(maxDep\) 信息,每次操作是 \(O(dep)\) 的,所以总复杂度是 \(O(T2 ^ hh)\) 的。

#include <iostream>
#include <cstdio> using namespace std; const int N = 3000005; typedef long long LL; int h, g, a[N], dep[N], maxDep[N], adj[N], tot; LL ans; void inline pushup(int p) {
maxDep[p] = max(dep[p], a[p << 1] > a[p << 1 | 1] ? maxDep[p << 1] : maxDep[p << 1 | 1]);
} void del(int p) {
a[p] = 0;
if (!a[p << 1] && !a[p << 1 | 1]) { maxDep[p] = 0; return; }
else if (!a[p << 1]) a[p] = a[p << 1 | 1], del(p << 1 | 1);
else if (!a[p << 1 | 1]) a[p] = a[p << 1], del(p << 1);
else {
int t = a[p << 1] > a[p << 1 | 1] ? p << 1 : p << 1 | 1;
a[p] = a[t], del(t);
}
pushup(p);
} int main() {
int T; scanf("%d", &T);
while (T--) {
ans = tot = 0;
scanf("%d%d", &h, &g);
for (int i = 1; i < (1 << h); i++) {
scanf("%d", a + i);
a[i << 1] = a[i << 1 | 1] = 0;
dep[i] = dep[i >> 1] + 1;
ans += a[i];
}
for (int i = (1 << h) - 1; i; i--) pushup(i);
for (int i = 1; i < (1 << h); i++)
while (a[i] && maxDep[i] > g) {
ans -= a[i], adj[++tot] = i, del(i);
}
printf("%lld\n", ans);
for (int i = 1; i <= tot; i++) printf("%d " , adj[i]);
puts("");
}
return 0;
}

Codeforces Round #631 (Div. 1) A-C的更多相关文章

  1. Codeforces Round #631 (Div. 2) D. Dreamoon Likes Sequences (bitmasks +dp )

    https://codeforces.com/contest/1330/problem/D 题目大意:给出一个限制 d 与模数 m ,求出可以构造出的满足条件的数组 a 的个数,需要满足以下条件:   ...

  2. Codeforces Round #631 (Div. 2)

    Contest Info Practice Link Solved A B C D E F 4/6 O O Ø       O 在比赛中通过 Ø 赛后通过 ! 尝试了但是失败了 - 没有尝试 Solu ...

  3. Codeforces Round #631 (Div. 1) B. Dreamoon Likes Sequences 题解(思维+求贡献)

    题目链接 题目大意 让你构造一个严格单调上升的数组a满足\(1<=a_1<a_2<....a_n<=d\) 而且要使得这个数组的异或前缀和也满足严格单调上升,求有多少个满足条件 ...

  4. Codeforces Round #631 (Div. 2) D.Dreamoon Likes Sequences

    题目连接:Dreamoon Likes Sequences  题意:给你d和m,让你构造一个递增数组a,使数组b(i==1,b[i]=a[i] ; i>1, b[i]=b[i-1]^a[i])递 ...

  5. 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 ...

  6. Codeforces Round #354 (Div. 2) ABCD

    Codeforces Round #354 (Div. 2) Problems     # Name     A Nicholas and Permutation standard input/out ...

  7. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  8. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  9. Codeforces Round #279 (Div. 2) ABCDE

    Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems     # Name     A Team Olympiad standard input/outpu ...

随机推荐

  1. 希捷powerchoice磁盘休眠功能arm打包

    官方只提供了x86下面的包,没有提供arm下面的包,而我们的arm机器是32位的,需要编译一个支持armhf的二进制文件,这个文件只需要一个即可,但是编译是整套编译的,并且我们需要选定指定的版本,关闭 ...

  2. ceph单机多mon的实现

    ceph默认情况下是以主机名来作为mon的识别的,所以这个情况下用部署工具是无法创建多个mon的,这个地方使用手动的方式可以很方便的创建多个mon 1.创建mon的数据存储目录 mkdir /var/ ...

  3. React native路由跳转navigate、push、replace的区别

    由于没有系统的去学习RN,对路由跳转了解不多,只是跟着项目在做,抽点时间简单学习一下RN路由跳转方法区别,总结如下: 如上图,外部是一个栈容器,此时A页面在最底部,navigate到B页面,为什么此时 ...

  4. NUC972当检测到sd卡时,在sd卡驱动中操作gpio开启sd卡的电源,解决sd卡因低电压有时识别不正常的问题

    1.根据硬件原理图,找到对应控制sd卡电源的gpio引脚,并在sd卡驱动文件中定义操作改该引脚的宏 2.在sd卡检测函数中,使用glib增加开sd卡电源的操作,如此当sd卡每次被检测到时,驱动中就会自 ...

  5. Spring Cloud配置中心之Consul

    Consul不仅可以作为Spring Cloud中服务的注册中心,也可以作为其配置中心,这样一个系统就可以实现服务发现和统一配置,减少系统维护的麻烦,其中在使用Consul作为配置中心使用的过程中可以 ...

  6. 太湖杯writeup

    CheckInGame checkInGame本题是个js游戏 设置个断点后,之后修改时间即可,然后把游戏玩完就行. ezWeb 本题是模板注入,过滤了{}和"",用︷︸和无引号的 ...

  7. ATM管理系统(三)

    一.作业信息 博客班级 软件工程 作业要求 作业要求 作业目标 你理解的作业目标具体内容 学号 3180701218 二.题目要求 编写一个ATM管理系统,语言不限,要求应包括以下主要功能:(1)开户 ...

  8. 如何合理利用iMindMap中的模板创建思维导图

    思维导图的制作并不是一项简单的工作,尤其是对许多工作或学习有特殊要求的朋友而言,当我们需要应对不同场景制作不同的思维导图时,总不能都靠自己从头制作,这样难度比较大也比较耗时.而iMindMap(win ...

  9. Go-Web编程_表单_0x02_验证表单的输入

    开发Web的一个原则就是,不能信任用户输入的任何信息,所以验证和过滤用户的输入信息就变得非常重要,我们经常会在微博.新闻中听到某某网站被入侵了,存在什么漏洞,这些大多是因为网站对于用户输入的信息没有做 ...

  10. 【CF600E】Lomsat gelral——树上启发式合并

    (题面来自luogu) 题意翻译 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. ci <= n <= 1e5 裸题.统计时先扫一遍得到出 ...