ZR 七连 Day 1 游记
ZR 七连 Day 1 游记
游记篇
赛前搞笑事件
今天是第一场正睿,还是要 好好对待 的
$ 17:59:58 $ 还在吃饭
$ 17:59:59 $ 做出重要决定,先打着比赛,有空就吃一口包子
$ 18:00 $ 比赛开始
乐死
比赛开始了
先读一下第一题,发现比较简单,可以使用二维前缀和过掉,于是我写了一个代码,然后寄了
一顿调试,找了几个小错误,然后发现了一个大错,因为统计的是连续的两个方块的数量,所以在求子矩阵的时候需要切掉两排
切掉以后就过了,测了测大样例也过了
$ 18:30:14 $ 提交 $ T1 $
读了读 $ T2 $,然后就一顿吐槽出题人
想了半天,也不会 $ T2 $,然后就去看 $ T3 $
感觉是水题,一眼秒,然后看到数据范围 $ n \le 10^{18} $,当场就炸了,不过考虑到打朴素的暴力有 $ 40 $ 分,还是打了暴力,其实就是一个简单的 $ dp $,然后测了测大样例,过了
$ 19:35:17 $ 提交 $ T3 $
然后看了看 $ T4 $,可以打爆搜,然后就写了一个爆搜交了上去
$ 19:59:47 $ 提交 $ T4 $
预估分数:$ 100 + 0 + 40 + 20 = 160 $
事实上一分不差
之后就玩 $ florr.io $ 去了,还 $ 7 = 1 $ 出了粉 $ Wing $
题解篇
T1 雪豹
这道题的题目意思是寻找一个矩阵中所有的指定宽高的子矩阵中相邻的方块是不同颜色的数量大于 $ k $,颜色只有 $ 0, 1 $ 两种
然后我们一眼就发现是二维前缀和
我们设 $ sum_{i, j} $ 表示从 $ 1, 1 $ 到 $ i, j $ 中相邻方块不同颜色的数量
每次统计的时候只需要记录新的方块的左边和上边是不是不同的,如果是不同的就增加答案,即:
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + (g[i][j - 1] != g[i][j]) + (g[i - 1][j] != g[i][j]);
然后枚举所有的起点,用前缀和判断是否合法,数量这么求:
int nw = sum[k][l] - sum[i - 1][l] - sum[k][j - 1] + sum[i - 1][j - 1];
但是会发现,我们多统计了一点东西,也就是说,我们截出子矩阵,没有断开和原来相连的部分
我们可以这么统计(只以横排为例):
用 $ hh_{i, j} $ 表示第 $ i $ 行与上一行对应方块颜色不同的数量,第二维是前缀和
然后我们在记录答案的时候,要减去这个东西:
nw -= hh[i][l] - hh[i][j - 1];
列也是一样的
然后提交一下就 $ AC $ 了
完整代码如下:
# include <bits/stdc++.h>
# define int long long
using namespace std;
int n, m, h, w, kk;
char g[5005][5005];
int sum[5005][5005], hh[5005][5005], ll[5005][5005];
signed main () {
cin >> n >> m >> h >> w >> kk;
for (int i = 1; i <= n; ++ i) for (int j = 1; j <= m; ++ j) {
cin >> g[i][j];
g[i][j] = (g[i][j] == '1');
}
for (int i = 1; i <= n; ++ i) for (int j = 1; j <= m; ++ j) {
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + (g[i][j - 1] != g[i][j] && j != 1) + (g[i - 1][j] != g[i][j] && i != 1);
hh[i][j] = hh[i][j - 1] + (g[i][j] != g[i - 1][j]);
ll[i][j] = ll[i - 1][j] + (g[i][j] != g[i][j - 1]);
}
int ans = 0;
for (int i = 1; i <= n - h + 1; ++ i) for (int j = 1; j <= m - w + 1; ++ j) {
int k = i + h - 1, l = j + w - 1;
int nw = sum[k][l] - sum[i - 1][l] - sum[k][j - 1] + sum[i - 1][j - 1];
if (i != 1) nw -= hh[i][l] - hh[i][j - 1];
if (j != 1) nw -= ll[k][j] - ll[i - 1][j];
if (nw >= kk) ++ ans;
}
cout << ans << endl;
return 0;
}
T2 猞猁
每次可以在相邻的两个数中把两个数各减 $ 1 $,并且 $ 1 $ 和 $ n $ 相邻,求能否让所有的数都变成 $ 0 $
我们假设在第一个地方操作 $ x $ 次,第二个地方操作 $ a_2 - x $ 次,第三个地方操作 $ a_3 - a_2 + x $ 次,以此类推,第 $ n $ 个地方操作 $ a_n - a_{n - 1} + \dots + (-1)^{n + 1}x $ 次
然后我们发现,在 $ n $ 个地方操作的次数加上第一个地方操作的次数相加等于 $ a_1 $
然后我们就可以发现,如果 $ n $ 是偶数,我们就可以把式子写出来,$ x $ 被抵消了,判断左边和右边是否相等,输出 $ 1 $ 或者 $ 0 $ 即可
如果 $ n $ 是奇数,就把 $ x $ 解出来,然后判断是否在上下界里面,输出 $ 1 $ 或者 $ 0 $ 即可
接下来讲解细节
首先,我们用一个变量 $ b $ 存储 $ a_n - a_{n - 1} + \dots + (-1)^{n}a_2 $
循环,每次 $ b = a_i - b $,然后记录变量 $ k $ 判断正负,每次 $ k = -k $
然后推式子,偶数的情况如下:
$ a_n - a_{n - 1} + \dots + a_2 = b $
所以我们的式子变成了 $ b - x + x = a_1 $
即 $ b = a_1 $
然后我们只需要判断上面的式子是否满足就可以了
奇数的情况如下:
$ a_n - a_{n - 1} + \dots - a_2 + x + x = a_1 $
同样的,我们用 $ b $ 代替前面一坨,得到 $ b + 2x = a_1 $
可以求出 $ x $
接下来求上下界
首先对于每个 $ a_i $,我们需要考虑正负问题,如果当前 $ x $ 是负的,那么 $ x $ 能取到最大值就让式子为 $ 0 $,因为 $ x $ 越大,式子越小,反之,$ x $ 取到的最小值就让式子最大,式子的最大值不能超过 $ a_i $,所以取 $ b - a_i $
如果 $ x $ 是正的,那我们就考虑相反的问题,如果 $ x $ 越大,式子越大,最大不超过 $ a_i $,所以可以取 $ a_i - b $,最小的话,可以取 $ -b $
然后就可以切掉这道题了
完整代码如下:
# include <bits/stdc++.h>
# define int long long
using namespace std;
int n, a[500005];
inline void solve () {
cin >> n;
for (int i = 1; i <= n; ++ i) cin >> a[i];
int k = 1, b = 0, minx = 0, maxx = a[1];
for (int i = 2; i <= n; ++ i) {
k *= -1;
b = a[i] - b;
if (k == 1) {
minx = max (minx, -b);
maxx = min (maxx, a[i] - b);
}
else {
maxx = min (maxx, b);
minx = max (minx, b - a[i]);
}
}
if (k == -1) {
if (b == a[1]) puts ("1");
else puts ("0");
}
else {
int x = (a[1] - b) / 2;
if (x * 2 == a[1] - b) {
if (minx <= x && x <= maxx) puts ("1");
else puts ("0");
}
else puts ("0");
}
}
signed main () {
int t; cin >> t; while (t --) solve ();
return 0;
}
T3 土拨鼠
题意是有一个集合 $ S $,每次可以走集合里的步数,每从一个位置离开,就可以拿走任意一个萝卜,也可以不拿,每个萝卜都不同
求从 $ 1 $ 走到 $ n $ 有多少种不同的方案
很简单,我们可以考虑 dp,设 $ dp_i $ 表示走到位置 $ i $ 的方案,这里不统计在位置 $ i $ 的萝卜拿法
然后我们就考虑位置 $ i $ 有 $ i + 1 $ 种方案
这样我们可以写出转移:
$ dp_i = \sum_{j \in S} dp_{i - j} \times (i - j + 1) $
然后我们发现 $ n $ 很大,所以 dp 行不通,考虑矩阵快速幂
我们初始矩阵竖着排,最上面是 $ dp_i $,最下面是 $ dp_{i - 14} $
然后我们考绿把这个矩阵变成最上面是 $ dp_{i + 1} $
也就是说,第一行需要把能通过当前的 $ dp_j $ 转移到 $ dp_i $ 的数字的对应值设为对 $ 2027 $ 取模的值,之后后面所有的行都直接把行号减一的列对应值设为 $ 1 $,其他的全是 $ 0 $ 就可以了
这样我们得到了 $ 2027 $ 个矩阵,每次的话是轮流乘
这样我们就先把 $ 2027 $ 个矩阵的乘积求出来,然后看看有几个完整的,只有一个不完整的,这样复杂度就大大降低
代码如下:
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int mod = 2027;
struct Mat {
int a[20][20];
Mat () {
memset (a, 0, sizeof (a));
}
inline Mat operator * (const Mat b) const {
Mat ans;
for (int i = 1; i <= 15; ++ i) for (int j = 1; j <= 15; ++ j) for (int k = 1; k <= 15; ++ k) {
(ans.a[i][j] += a[i][k] * b.a[k][j] % mod) %= mod;
}
return ans;
}
inline void init () {
memset (a, 0, sizeof (a));
for (int i = 1; i <= 15; ++ i) a[i][i] = 1;
}
} tzf[3005] ;
int n, m; bool vis[35];
inline Mat ksm (Mat a, int b) {
Mat ans;
ans.init ();
for (; b; b >>= 1, a = a * a) {
if (b & 1) ans = ans * a;
}
return ans;
}
signed main () {
cin >> n >> m;
for (int i = 1; i <= m; ++ i) { int x; cin >> x; vis[x] = 1; }
for (int k = 0; k <= mod - 1; ++ k) {
for (int i = 1; i <= 15; ++ i) if (vis[i]) tzf[k].a[1][i] = k;
for (int i = 2; i <= 15; ++ i) tzf[k].a[i][i - 1] = 1;
}
int s = n / mod, laz = n % mod;
Mat sum;
sum.init ();
for (int i = 1; i <= mod; ++ i) sum = sum * tzf[i % mod];
Mat ans; ans.a[1][1] = 1;
ans = ans * ksm (sum, s);
sum.init ();
for (int i = 1; i <= laz; ++ i) sum = sum * tzf[i % mod];
ans = ans * sum;
cout << ans.a[1][1] << endl;
return 0;
}
T4 芝士
我们考虑二分答案 $ k $,接下来考虑 check 怎么写
我们这么考虑,前两个随便放,然后其他的有一个范围,如果超出了范围就直接返回 $ 0 $
设大范围是 $ L, R $,小范围是 $ l, r $,初始大范围是左边,小范围是右边,如果两个范围都可以的话,就找一个最优的
我们可以把大范围设为两个区间合并后更大的范围,好像就是并,然后小范围就是当前的范围,也就是 $ [a_i - k, a_i + k] $
接下来如果只能满足一个范围,就直接放就可以了,并更新
都不满足就返回 $ 0 $
这是最简单的题,但是思维较难
代码如下:
# include <bits/stdc++.h>
using namespace std;
int n, a[1000005];
inline bool check (int k) {
int l1 = a[1] - k, r1 = a[1] + k;
int l2 = a[2] - k, r2 = a[2] + k;
if (a[2] < l1 || a[2] > r1) return 0;
for (int i = 3; i <= n; ++ i) {
if (a[i] > r1 || a[i] < l1) {
if (a[i] > r2 || a[i] < l2) return 0;
l2 = a[i] - k, r2 = a[i] + k;
}
else if (a[i] > r2 || a[i] < l2) {
l1 = a[i] - k, r1 = a[i] + k;
}
else {
l1 = min (l1, l2);
r1 = max (r1, r2);
l2 = a[i] - k, r2 = a[i] + k;
}
}
return 1;
}
signed main () {
cin >> n; for (int i = 1; i <= n; ++ i) cin >> a[i];
int l = 0, r = 1e9, ans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (check (mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
cout << ans << endl;
return 0;
}
ZR 七连 Day 1 游记的更多相关文章
- NOIp2016 游记
DAY -2 不要问我为什么现在就开了一篇博客. 本来想起个NOIp2016爆零记或者NOIp2016退役记之类的,但是感觉现在不能乱立flag了.所以就叫游记算了. 前几场模拟赛崩了一场又一场,RP ...
- CTSC2016&&APIO2016滚粗记&&酱油记&&游记<del>(持续更新)</del>
挖一波坑 #include <cstdio> using namespace std; int main(){ puts("转载请注明出处:http://www.cnblogs. ...
- python--爬虫入门(七)urllib库初体验以及中文编码问题的探讨
python系列均基于python3.4环境 ---------@_@? --------------------------------------------------------------- ...
- 【20171026早】alert(1) to win - 第六、七、八题
早上7点起床,又写了一篇小说发在了起点网上,有兴趣的可以看看.点击这里 忙完后,继续练习,刚开始发现自己答题的速度有些慢,可能是因为对于html,javascript知识不是很精通,但是话又说回来,谁 ...
- ThoughtWorks University之旅 —— 印度游记
ThoughtWorks University是ThoughtWorks为新加入的员工提供的入职培训项目之一,会将世界各地office新入职的员工一起带到印度浦那,参加一次为期5周的培训,内容涵盖了公 ...
- PKUWC 2018游记
PKUWC 2018游记 标签: Day\([-inf,0)\) 停课之后一直各种浪的飞起,考试rank20+,不搞颓但是学习很没有状态.还经常带着耳机被谢总抓了好几次,然后被拉过去谈话了好几次... ...
- NOIWC2018游记
NOIWC2018游记 接着PKUWC就是NOIWC了.感觉时间很紧呀,但越是紧张呢,就越让人心里觉得充实. 能够去NOIWC,应该是一次非常充实的体验吧. 这一篇游记是接着上一篇写的,时间点上完全都 ...
- SDOI 2019 R1游记
$SDOI$ $2019$ $R1$游记 昨天才刚回来,今天就来写游记啦! Day -5: 做了一下去年省选的Day1,感觉很神仙. Day -4: 做了一下去年省选的Day2,感觉还是很神仙. Da ...
- [原]Jenkins(七)---jenkins项目编译测试发布由maven构建的web项目
/** * lihaibo * 文章内容都是根据自己工作情况实践得出. * 版权声明:本博客欢迎转发,但请保留原作者信息! http://www.cnblogs.com/horizonli/p/533 ...
- 【游记】CCHO TY国初划水记
没想到第一篇游记竟然是化学国初(其实是上次SXACM时候懒得写 DAY0 一下午做了5个小时的校车,服务区水真贵 肝了4个小时模拟题,颠到崩溃. 下榻在距离山大附不远的一个酒店,高三人好多哇,我们年级 ...
随机推荐
- 改变函数内this指向方法——call、apply、bind
javascript为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部this的指向问题,常用的有bind( ).call( ).apply( )三种方法. 相同点: 都可以改变函数内部的thi ...
- 小白学标准库之 http
1. 前言 标准库是工具,是手段,是拿来用的.一味的学标准库就忽视了语言的内核,关键.语言层面的特性,内存管理,垃圾回收.数据结构,设计模式.这些是程序的内核,要熟练,乃至精通它们,而不是精通标准库. ...
- 13个构建RESTful API的最佳实践
前言 Facebook.GitHub.Google和其他许多巨头都需要一种方法来服务和消费数据.在今天的开发环境中,RESTful API仍然是服务和消费数据的最佳选择之一. 但你是否考虑过学习行业标 ...
- redis-持久化-RDB-AOF.png
- Java开发者的Python快速进修指南:探索15种独特的Python特殊方法
概述 在Python中,特殊方法(也称为魔术方法)是由Python解释器自动调用的,我们不需要手动调用它们,而是使用内置函数来间接地使用它们.举个例子,我们可以实现特殊方法__len__(),然后通过 ...
- Numa以及其他内存参数等对Oracle的影响
Numa以及其他内存参数等对Oracle的影响 背景知识: Numa的理解 Numa 分一致性内存访问结构 主要是对应UMA 一致性内存访问而言的. 在最初一个服务器只有一个CPU的场景下, 都是UM ...
- Nginx双层域名时 iframe嵌入/跳转页面的处理过程
Nginx双层域名时 iframe嵌入/跳转页面的处理过程 背景 两年前在上一家公司内遇到一个Nginx的问题 当时的场景是 双层nginx代理时(一层域名侧, 一层拆分微服务的网关层) 程序里面会打 ...
- [转帖]jmeter实现分布式压测
分布式实现的前提条件: 1.master机器和奴隶机的jmeter要一致 a. jmeter版本要一致 b.jdk主要版本要一致,比如都是jdk1.8,后面的小版本不一样不影响 c.jmeter脚本中 ...
- [转帖]优化命令之iotop命令
文章目录 引言 一.iotop简介 1.iotop安装 2.iotop语法 3.iotop参数 二.I/O的常用快捷键 三.交互模式 四.iotop示例 1.只显示正在产生I/O的进程 2.显示指定P ...
- [转帖]15 个必须知道的 chrome 开发工具技巧
在Web开发者中,Google Chrome是使用最广泛的浏览器.六周一次的发布周期和一套强大的不断扩大开发功能,使其成为了web开发者必备的工具.你可能已经熟悉了它的部分功能,如使用console和 ...