当前位置: 首页 > news >正文

EPIC Institute of Technology Round August 2024 (Div. 1 + Div. 2)

前言

        又是一场压线不掉分的比赛。

        Standings:2706

        题目链接:Dashboard - EPIC Institute of Technology Round August 2024 (Div. 1 + Div. 2) - Codeforces

A. Distanced Coloring

        题意:

        给一个 n * m 的矩阵,涂色,要求任意两个相同颜色的块,他们横纵坐标差值的最大值不超过 k ,问涂色至少需要几种颜色。

        思路:

        很显然要让每种颜色的格子呈现一种最紧凑的排列方式,于是每隔 k 个位置放一样的颜色。

#include<cstdio>
#include<cstring>
using namespace std;int T,n,m,k;int min(int x,int y) { return x < y ? x : y ; }int main()
{scanf("%d",&T);while (T --){scanf("%d%d%d",&n,&m,&k);if(n < m){int tmp = n;n = m;m = tmp;}int x = min(n,k);printf("%d\n",x * min(k,m));}return 0;
}

B. Removals Game

        题意:

        给两个序列 a 和 b ,Alice 和 Bob 依次取走一个数,只能取两端的数,若两个人最后剩下的那个数相等则 Bob 获胜,反之 Alice 获胜。

        思路:

        容易发现 Bob 必须要 “跟着 Alice 取” 才能获胜,手模一下可以发现 a 和 b 必须是一致的或者互为逆序列才能让 Bob 获胜,否则 Alice 必胜。

        (比赛时代码打得有点丑)

#include<cstdio>
#include<cstring>
using namespace std;#define N 300005int T,n,a[N],b[N];int main()
{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]);int la,ra,lb,rb,flag;la = lb = 1,ra = rb = n,flag = 0;while (la <= ra){if((a[la] != b[lb] && a[la] != b[rb]) || (a[ra] != b[lb] && a[ra] != b[rb])){flag = 1;break;}if(a[la] == b[lb]) ++ la,++ lb;else ++ la,-- rb;}if(flag) printf("Alice\n");else printf("Bob\n");}return 0;
}

C. Black Circles

        题意:

        给你一些圆心,一个起点和一个终点,这些圆初始的半径是零,半径随时间均匀增加,你需要从起点走到终点,速度和半径增加的速率相同,判断走到终点的过程中会不会碰到圆。

        思路:

        显然要走直线,只需判断当人走到终点时有没有圆已经扩散到终点即可。

        因为如果人和圆在终点前的某处会相交,那说明人到终点的时候圆一定也到了,因此我们只需判断终点处即可。

      (比赛时看错了一个样例数据然后对题目各种猜想并百思不能其解浪费了很多时间。。。)

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;#define N 100005int T,n;
long long x[N],y[N],xs,ys,xt,yt,dis;long long count(long long x1,long long y1,long long x2,long long y2)
{return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}int main()
{scanf("%d",&T);while (T --){scanf("%d",&n);for (int i = 1;i <= n;++ i) scanf("%lld%lld",&x[i],&y[i]);scanf("%lld%lld%lld%lld",&xs,&ys,&xt,&yt);dis = count(xs,ys,xt,yt);int flag = 1;for (int i = 1;i <= n;++ i){long long now = count(x[i],y[i],xt,yt);if(now <= dis){flag = 0;break;}}if(flag) printf("YES\n");else printf("NO\n");}return 0;
}

D1. DFS Checker (Easy Version)

        题意:

        给一棵从 1 ~ n 标号的满二叉树和一个长度为 n 的排列 p,每次询问交换 p 中的两个值,判断能否使得到的新序列成为这课满二叉树的一种 dfs 序。其中询问的交换操作是持久化的,

        思路:

        思考一下满二叉树的特性:所有非叶子节点 k 有且仅有 2 个儿子,且儿子的编号分别为 k + 1 和 k + son[k] + 1 (这里 son[k] 表示 k 的左边或右边子树的大小)。

        想到这其实问题就迎刃而解了。我们暴力的想法就是扫一遍 p 数组,判断每一位 k 的儿子是否在合法的位置( k + 1 或 k + son[k] + 1 )上即可。这里询问只会改变两个数 x 和 y ,而对每个位置是否合法产生的影响只有 x ,y 及其前后的位置,因此我们可以做如下优化:统计当前 p 数组内合法的位置,每次询问更改对应位置上的 bool 值以及当前合法的位置总数,若某次操作后得到全部位置都合法,那就说明这是一个符合条件的 dfn 。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;#define N 500005int T,n,q,p[N],f[N],id[N],son[N],now;void change(int k,int w)
{if(w){if(!f[k]) f[k] = 1,++ now;}else{if(f[k]) f[k] = 0,-- now;}return;
}void check(int k)
{int x,y;int bz = 0;if(k >= (n + 1) / 2) bz = 1;else{x = k * 2,y = k * 2 + 1;if(id[k] + son[k] + 1 <= n){if(p[id[k] + 1] == x && p[id[k] + son[k] + 1] == y){if(f[x] && f[y]) bz = 1;}if(p[id[k] + 1] == y && p[id[k] + son[k] + 1] == x){if(f[x] && f[y]) bz = 1;}}}change(k,bz);return;
}int main()
{scanf("%d",&T);while (T --){scanf("%d%d",&n,&q);for (int i = 1,x;i < n;++ i) scanf("%d",&x);for (int i = 1;i <= n;++ i) scanf("%d",&p[i]),id[p[i]] = i,f[i] = 0;for (int i = n; i ;-- i){if(i >= (n + 1) / 2) son[i] = 0;else son[i] = son[i * 2] * 2 + 1;}for (int i = n,x,y; i ;-- i){if(i >= (n + 1) / 2) f[i] = 1;else{x = i * 2,y = i * 2 + 1;if(id[i] + son[i] + 1 > n) continue;if(p[id[i] + 1] == x && p[id[i] + son[i] + 1] == y){if(f[x] && f[y]) f[i] = 1;}if(p[id[i] + 1] == y && p[id[i] + son[i] + 1] == x){if(f[x] && f[y]) f[i] = 1;}}}now = 0;for (int i = 1;i <= n;++ i) now += (f[i]);while (q --){int x,y,tmp;scanf("%d%d",&x,&y);tmp = p[x],p[x] = p[y],p[y] = tmp;x = p[x],y = p[y];tmp = id[x],id[x] = id[y],id[y] = tmp;while (x && y){if(x > y) check(x),x >>= 1;else if(x < y) check(y),y >>= 1;else check(y),check(x),x >>= 1,y >>= 1;}if(now == n) printf("YES\n");else printf("NO\n");}}return 0;
}

D2. DFS Checker (Hard Version)

        题意:

        和 Easy Version 的区别:给的不是一棵满二叉树,而是更普遍的任意树。

        思路:

        这样一来每个节点的儿子数目就不确定了,若某个节点的孩子很多,询问又总是包含这个节点,那么势必会超时,我们需要考虑更普适的方法。

        从 p 数组入手,思考一下合法的 dfn 数组每个位置上的点和前后位置上的点有什么关系:结论是 “要么前一个点是后一个点的父亲,要么前一个点是叶子节点并且这两个点的 lca 是后一个点的父亲” 。这个结论容易理解,是合法的 dfn 数组的必要条件,关键是这个结论是否是充分条件。

        当然是。倘若数组 p 的每个位置都符合上述条件,那么我们从叶子节点往上思考,每一层都一定是合法的,这样整棵树也必然是可以构造出来的。

        因此我们还是按照类似 Easy Version 的做法,统计当前 p 数组里有多少个合法位置,每次询问操作进行修改即可。

#include<cstdio>
#include<cstring>
using namespace std;#define N 300005int T,n,q,f[N][22],st[N],dep[N],p[N],leaf[N],bz[N],lg[N],cnt,now;struct Edge
{int next,to;
}ed[N << 1];void add(int u,int v)
{ed[++ cnt].next = st[u];ed[cnt].to = v;st[u] = cnt;return;
}void dfs(int x,int fa)
{dep[x] = dep[fa] + 1;for (int i = 1;(1 << i) <= dep[x];++ i)f[x][i] = f[f[x][i - 1]][i - 1];int flag = 1;for (int i = st[x]; ~i ;i = ed[i].next)if(ed[i].to != fa){dfs(ed[i].to,x);flag = 0;}leaf[x] = flag;return;
}int lca(int x,int y)
{if(dep[x] < dep[y]){int tmp = x;x = y,y = tmp;}while (dep[x] > dep[y]) x = f[x][lg[dep[x] - dep[y]]];if(x == y) return x;for (int i = lg[dep[x]];i >= 0;-- i)if(f[x][i] != f[y][i])x = f[x][i],y = f[y][i];return f[x][0];
}int check(int x)
{int f1,f2;f1 = f2 = 0;if(x > 1){if(p[x - 1] == f[p[x]][0]) f1 = 1;else if(lca(p[x - 1],p[x]) == f[p[x]][0] && leaf[p[x - 1]]) f1 = 1;}else f1 = 1;if(x < n){if(p[x] == f[p[x + 1]][0]) f2 = 1;else if(lca(p[x],p[x + 1]) == f[p[x + 1]][0] && leaf[p[x]]) f2 = 1;}else f2 = 1;return (f1 & f2) ;
}void change(int k,int w)
{if(k < 1 || k > n) return;if(!bz[k] && w) bz[k] = 1,++ now;else if(bz[k] && !w) bz[k] = 0,-- now;return;
}int main()
{lg[1] = 0;for (int i = 2;i <= 300000;++ i) lg[i] = lg[i >> 1] + 1;scanf("%d",&T);while (T --){scanf("%d%d",&n,&q),st[1] = -1,dep[0] = f[1][0] = cnt = now = 0;for (int i = 2;i <= n;++ i) scanf("%d",&f[i][0]),add(i,f[i][0]),add(f[i][0],i),st[i] = -1;dfs(1,0);for (int i = 1;i <= n;++ i) scanf("%d",&p[i]);for (int i = 1;i <= n;++ i) bz[i] = check(i),now += bz[i];while (q --){int x,y,tmp;scanf("%d%d",&x,&y);tmp = p[x],p[x] = p[y],p[y] = tmp;change(x,0),change(x - 1,0),change(x + 1,0);change(y,0),change(y - 1,0),change(y + 1,0);change(x,check(x)),change(y,check(y));if(x > 1) change(x - 1,check(x - 1));if(x < n) change(x + 1,check(x + 1));if(y > 1) change(y - 1,check(y - 1));if(y < n) change(y + 1,check(y + 1));if(now == n) printf("YES\n");else printf("NO\n");}}return 0;
}

E. Cosmic Rays

        题意:

        给一个序列 s ,每秒钟宇宙射线都会辐射这个序列,使得所有 s_i \neq s_{i - 1} 的 s_i 消失。序列 s 以 (a,b)对的形式给出,表示每个 b 有 a 个,对于所有的 i = 1,2,...,n ,计算前 i 组数形成的序列 s 变成空序列花费的时间。

        思路:

        一眼单调栈,维护每组数前面的 “佼佼者” ,即到这组数之前能最后剩下的那组数。

        若当前这组数可以直接或者通过跨越与前面的数合并,那么更新当前的佼佼者。

        若当前这组数的个数没有前面的多,那意味着无法跨越到前面去合并。

        单调栈维护即可。

#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;#define N 300005int T,n;
long long a[N],b[N],ans;stack<long long> st;long long max(long long x,long long y) { return x > y ? x : y ; }int main()
{int num = 0;scanf("%d",&T);while (T --){scanf("%d",&n),ans = 0ll;for (int i = 1;i <= n;++ i) scanf("%lld%lld",&a[i],&b[i]);while (!st.empty()) st.pop();for (int i = 1;i <= n;++ i){long long now = 0ll;while (!st.empty() && ((b[st.top()] != b[i] && a[i] >= a[st.top()]) || (b[st.top()] == b[i]))){if(b[st.top()] != b[i]) now = max(now,a[st.top()]);else{int las = st.top();a[i] = a[i] + a[las] - now;}st.pop();}st.push(i);ans = max(ans,a[i]);++ num;printf("%lld ",ans);}printf("\n");}return 0;
}

总结

        貌似还是前面的题目太容易卡了,div 2 后面的 EF 题很多时候都是可做的但是没有时间,甚至有时候 D 都没开出来,可能需要多练练 B 这种小巧玲珑的思维题。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 大模型日报 2024-08-16
  • vim中跳转头文件
  • JS DOM、点击事件
  • C++ 设计模式——简单工厂模式
  • 忽略时间戳,快速对比tcpreplay和tcpdump数据包pcap数据包一致性
  • 开发军用LabVIEW程序注意事项
  • centos虚拟机IP地址频繁变化的原因及解决策略
  • eNSP 华为远程访问路由器
  • c语言学习,malloc()函数分析
  • 数据库:数据查询
  • Android大脑--systemserver进程
  • 杂项:WPF编程指南 第一章
  • Linux - 基础工具使用
  • 18. 基于ES实战海量数据检索
  • Java实习记录 8 ——使用 XSSFWorkbook 实现复杂表格下载(背景色、对齐方式、单元格合并等操作)
  • 2017届校招提前批面试回顾
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • idea + plantuml 画流程图
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • ReactNative开发常用的三方模块
  • Web设计流程优化:网页效果图设计新思路
  • 测试如何在敏捷团队中工作?
  • 记一次和乔布斯合作最难忘的经历
  • 聊聊flink的BlobWriter
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  •  一套莫尔斯电报听写、翻译系统
  • 主流的CSS水平和垂直居中技术大全
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • #AngularJS#$sce.trustAsResourceUrl
  • #includecmath
  • #微信小程序:微信小程序常见的配置传旨
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (10)STL算法之搜索(二) 二分查找
  • (2)MFC+openGL单文档框架glFrame
  • (26)4.7 字符函数和字符串函数
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (笔试题)分解质因式
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (理论篇)httpmoudle和httphandler一览
  • (七)Java对象在Hibernate持久化层的状态
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (算法设计与分析)第一章算法概述-习题
  • (转)可以带来幸福的一本书
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • .net core 6 redis操作类
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET 动态调用WebService + WSE + UsernameToken
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • /etc/fstab 只读无法修改的解决办法
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • []利用定点式具实现:文件读取,完成不同进制之间的