2021 BNU Winter Training 9 (The 14th Chinese Northeast Collegiate Programming Contest)

训练网址

A. Micro Structure Thread

  • 这道题题解都搜不到啊,但是听说可以转化为最小生成树

B. Team

  • 网络流

C. Liner vectors

  • 要求构造一个 N * N 的矩阵,矩阵的每个元素都由0或1构成。矩阵的每一行元素之和都是K。要求这个矩阵的任意一个行向量不能被其他若干向量异或表示出来。
  • 线性基,其实就是要求这个矩阵的秩为N
  • 观察样例,其实有一个很简单的方法(N = 5, K = 3)
    (0011101011011010111010011)\begin{pmatrix} 0 & 0 & 1 & 1 & 1 \\ 0 & 1 & 0 & 1 & 1 \\ 0 & 1 & 1 & 0 & 1 \\ 0 & 1 & 1 & 1 & 0 \\ 1 & 0 & 0 & 1 & 1 \end{pmatrix} ⎝⎜⎜⎜⎜⎛​00001​01110​10110​11011​11101​⎠⎟⎟⎟⎟⎞​
  • 你会发现,前 K + 1 行在右侧构成了一个 (K+1)×(K+1)(K + 1) \times(K + 1)(K+1)×(K+1) 的矩阵,类似于对角矩阵,不过对角线是0,其他元素是1. 然后剩下 K + 2 ~ N 行,每行最前面只填1个1. 最后 K−1K - 1K−1 个数也填1. 这样子,显然,当K为奇数时,前 K + 1 行是线性无关的(每行每列都有奇数个1,异或起来一定不是0)。K+2K + 2K+2 ~ NNN 行是阶梯型矩阵反过来了,也是线性无关的。而前后两部分也是线性无关的。
  • 至于不合法情况,显然 N == K 时是不合法的。然后若 K 为偶数,那么全部异或起来一定是0,也不合法。
  • 这个构造方法是真的巧妙啊。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef unsigned long long ll;
ll a[70];
int main() {int T;scanf("%d", &T);while (T--) {int N, K;scanf("%d%d", &N, &K);if (N == 1) printf("1\n");else if (N == K || K % 2 == 0) printf("-1\n");else {for (int i = 0; i < K + 1; i++) {a[i] = (1LL << K + 1) - 1;a[i] ^= (1LL << (K - i));}for (int i = K + 1; i < N; i++) {a[i] = (1LL << (K - 1)) - 1;a[i] ^= (1LL << i);}for (int i = 0; i < N; i++) {printf("%llu%c", a[i], i + 1 == N ? '\n' : ' ');}}}return 0;
}

D. PepperLa’s String

  • 题意:给字符串可以删去一个字符,可以把连续的字符替换成字符加十六进制数,求压缩后的字符串最短前提下,压缩后字符串的字典序最小。
  • 分类讨论的情况很多,容易漏。

推荐题解

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int maxn = 1000010;
char str[maxn], ch[maxn];
int tot[maxn], n, m;
string dec_to_hex(int x) {//注意进制转换最好写成 do-while 的形式,用while的话可能会让无法转换0.string res;do {int xx = x % 16;res += (xx >= 10) ? (xx - 10 + 'A') : (xx + '0');x /= 16;} while (x);reverse(res.begin(), res.end());return res;
}
void solve() {n = strlen(str);m = 0;//如果只有一个字符,那么什么也不输出if (n == 1) return;//先统计有多少个连续字母for (int i = 0, cnt; i < n; i++) {if (i == 0 || str[i] != str[i - 1]) {cnt = 1;}else cnt++;if (i == n - 1 || str[i] != str[i + 1]) {//每一段相同的字母信息存进ch和tot里面ch[m] = str[i];tot[m] = cnt;m++;}}//del_pos 表示要删除字母的位置。del_pos = 0 表示字符串长度不能减小/*三种字符串长度会变小的情况,贪心策略如下(1)只有1个字符,删去之后为空。这时若 s[i] > s[i + 1] 就选择它 (break),否则就往后继续找(2)两个字符,删掉变成一个字符,由于ASCII: 数字 < 字母,因此只有它是最后一个字母时才选择(3)十六进制下,100... 减一变成 FF... 因此只有是最后一个字母时才选择它*/int del_pos = 0;for (int i = 0; i < m; i++) {if (tot[i] == 1) {del_pos = i;if (i == m - 1 || ch[i] > ch[i + 1]) break;}else if (tot[i] == 2 || dec_to_hex(tot[i]).size() > dec_to_hex(tot[i] - 1).size()) {del_pos = i;}}//for (int i = 0; i < m; i++) {//  printf("%c %d %s\n", ch[i], tot[i], dec_to_hex(tot[i]).c_str());//}tot[del_pos]--;for (int i = 0; i < m; i++) {if (tot[i] == 0) continue;cout << ch[i];if(tot[i] > 1) cout << dec_to_hex(tot[i]);}cout << endl;
}
int main() {while (cin >> str) {solve();}return 0;
}
/*
aabbbbbbbbbbbbbbbbb
aabbbbbbbbbbbbbbbb
aaacccccccccc
aaabaaa
abcdef
*/

E. PepperLa’s Cram School

F. PepperLa’s Boast

  • 从 (1,1)(1, 1)(1,1) 走到 (N,M)(N, M)(N,M), 一步可以走三个方向,每次可以走一步(不可以走到 aij≤0a_{ij} \le 0aij​≤0 的地方),也可以消耗 U 走最多 K 步(可以少于K步),求到终点最大值。
  • 只有 a(i,j)>0a(i, j) > 0a(i,j)>0 才更新 f(i,j)f(i, j)f(i,j)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<deque>
using namespace std;
const int maxn = 1010;
typedef long long ll;
ll a[maxn][maxn], f[maxn][maxn];
ll N, M, K, U;
deque<int> col[maxn];
typedef pair<ll, int> P;
void update(ll& x, const ll& y) {if (x < y) x = y;
}
void solve() {for (int j = 1; j <= M; j++) col[j].clear();deque<P> row;f[1][1] = a[1][1];for (int i = 1; i <= N; i++) {row.clear();for (int j = 1; j <= M; j++) {while (col[j].size() && col[j].front() < i - K) col[j].pop_front();while (row.size() && row.front().second < j - K) row.pop_front();if (a[i][j] > 0) {// 走一步,不憋气if (f[i - 1][j] != -1) update(f[i][j], f[i - 1][j] + a[i][j]);if (f[i][j - 1] != -1) update(f[i][j], f[i][j - 1] + a[i][j]);if (f[i - 1][j - 1] != -1) update(f[i][j], f[i - 1][j - 1] + a[i][j]);// 从某一个远地方憋着气到这个地方// 首先更新当前小矩阵的最大值if (col[j].size()) {while (row.size() && row.back().first <= f[col[j].front()][j]) row.pop_back();row.push_back({ f[col[j].front()][j], j });}//然后更新憋气到这个地方if (row.size()) {update(f[i][j], row.front().first + a[i][j] - U);}//因为要把 f[i][j] 更新这个小矩阵。因此如果上面更新了,要把更新的col弄出来if (col[j].size()) row.pop_back();}//更新小矩阵的值//先更新列滑动窗口if (f[i][j] >= U) {while (col[j].size() && f[col[j].back()][j] <= f[i][j]) col[j].pop_back();col[j].push_back(i);}//再更新行滑动窗口if (col[j].size()) {while (row.size() && row.back().first <= f[col[j].front()][j]) row.pop_back();row.push_back({f[col[j].front()][j], j});}}}cout << f[N][M] << endl;
}
int main() {memset(f, -1, sizeof f);while (cin >> N >> M >> K >> U) {for (int i = 1; i <= N; i++) {for (int j = 1; j <= M; j++) {scanf("%lld", &a[i][j]);f[i][j] = -1;}}solve();}}

G. PepperLa’s Express

  • 题意:题意是有一些快递点和一些用户,一个用户的代价是到最近快递点的曼哈顿距离。要求增加一个快递点最小化用户代价的最大值。题目中的 “minimal dilivery time” 指的是求最小化的最大时间,而不是求最小时间。

  • 首先,我们可以根据 FloudFillFloud\ FillFloud Fill 模型(建立虚拟源点)求出每一个user到所有dilivery station的最近距离。

  • 我们设想的是,二分答案。然后大于二分结果的,我们看能否将所有的点都小于等于答案。二分的原因在于,我们可以在 O(1)O(1)O(1) 的时间内求出某个点到某些点的最大值。因此,我们要找到哪些点不满足条件。

  • 曼哈顿距离可以拆成这个样子,因为我们只关注所有点到 (xi,yi,zi)(x_i, y_i, z_i)(xi​,yi​,zi​) 的最大值。因此要取两次 maxmaxmax,因此,我们只需找到后面 (±xj,±yj,±zj)(\pm x_j,\pm y_j,\pm z_j)(±xj​,±yj​,±zj​) 每一项的最大值即可,就是这个样子

    代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 110;
char mz[maxn][maxn][maxn];
int dx[] = { 1, -1, 0, 0, 0, 0 }, dy[] = { 0, 0, 1, -1, 0, 0 }, dz[] = { 0, 0, 0, 0, 1, -1 };
int op[] = { 1, -1 };
int dist[maxn][maxn][maxn];
int X, Y, Z;
int mmax[8];
struct P {int z, x, y;
};
void bfs() {queue<P> que;for (int z = 1; z <= Z; z++) {for (int x = 1; x <= X; x++) {for (int y = 1; y <= Y; y++) {if (mz[z][x][y] == '@') {dist[z][x][y] = 0;que.push({ z, x, y });}else dist[z][x][y] = -1;}}}while (que.size()) {auto u = que.front(); que.pop();int z = u.z, x = u.x, y = u.y;for (int i = 0; i < 6; i++) {int zz = z + dz[i], xx = x + dx[i], yy = y + dy[i];if (zz < 1 || zz > Z || xx < 1 || xx > X || yy < 1 || yy > Y) continue;if (dist[zz][xx][yy] >= 0) continue;dist[zz][xx][yy] = dist[z][x][y] + 1;que.push({ zz, xx, yy });}}
}
bool check(int m) {memset(mmax, -0x3f, sizeof mmax);int cnt = 0;for (int z = 1; z <= Z; z++) {for (int x = 1; x <= X; x++) {for (int y = 1; y <= Y; y++) {// 要选出 距离大于m 的 用户if (dist[z][x][y] <= m || mz[z][x][y] != '*') continue;cnt++;for (int i = 0; i < 8; i++) {mmax[i] = max(mmax[i], -(op[i & 1] * z + op[(i >> 1) & 1] * x + op[(i >> 2) & 1] * y));}}}}//容易忽视这个特殊条件的判定if (cnt == 0) return true;for (int z = 1; z <= Z; z++) {for (int x = 1; x <= X; x++) {for (int y = 1; y <= Y; y++) {int res = -1;if (mz[z][x][y] == '.') {for (int i = 0; i < 8; i++) {res = max(res, mmax[i] + z * op[i & 1] + x * op[(i >> 1) & 1] + y * op[(i >> 2) & 1]);}if (res <= m) return true;}}}}return false;
}
void solve() {bfs();int l = 0, r = X + Y + Z;while (r > l) {int mid = (l + r) / 2;//小心二分别写错了呀if (check(mid)) r = mid;else l = mid + 1;}printf("%d\n", l);
}
int main() {while (cin >> Z >> X >> Y) {for (int z = 1; z <= Z; z++) {for (int x = 1; x <= X; x++) {scanf("%s", mz[z][x] + 1);}}solve();/*for (int i = 1; i <= X; i++) {for (int j = 1; j <= Y; j++) {printf("%d ", dist[1][i][j]);}printf("\n");}*/}return 0;
}

2021 BNU Winter Training 9 (2020CCPC东北四省赛)相关推荐

  1. 2021 HZNU Winter Training Day 17 (2018 German Collegiate Programming Contest (GCPC 18))

    2021 HZNU Winter Training Day 17 (2018 German Collegiate Programming Contest (GCPC 18)) 题目 A B C D E ...

  2. 2018东北四省赛 Store The Matrix (矩阵)

    2018东北四省赛 Store The Matrix (矩阵) 题目描述 Given a matrix M with r rows and c columns. It is obviously tha ...

  3. 【vjudge contest 418548】2021 BUAA Winter Training 3(Private),签到题ABCDG

    题目 A Amazing Pizza /* 题意:给出一个圆环和n个圆,求多少个圆在圆环内 思路:先检查它是否在大圆内,再检查它是否在小圆外. */ #include<bits/stdc++.h ...

  4. 2021 HZNU Winter Training Day 18

    目录 Solutions A. 星球大战starwar B. Median C. Obtain Two Zeroes D. Naive Operations E. Co-prime F. Lightn ...

  5. 2018东北四省赛 Spin A Web 曼哈顿距离最小生成树

    莫队的论文,讲的很清晰 问题描述:给定平面N个点,两边相连的代价为曼哈顿距离,求这些点的最小生成树 按一般想法,prime复杂度O(n^2),Kruskal复杂度O(n^2 logn),N很大时,这复 ...

  6. 东北四省赛H-Skyscraper-线段树的区间合并优化

    题目描述: At the main street of Byteland, there will be built n skyscrapers, standing sequentially one n ...

  7. 2021CCPC东北四省赛 D. Lowbit 势能线段树

    传送门 分析 分析一下x+lowbit(x)x + lowbit(x)x+lowbit(x)这个操作 如果多次操作之后,那么xxx中只会有最高位存在一,这个时候再执行一次操作就会使整个数字乘二 所以, ...

  8. 2021年大数据HBase(十四):HBase的原理及其相关的工作机制

    全网最详细的大数据HBase文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 HBase的原理及其相关的工作机制 一.HBase的flus ...

  9. 2021年大数据Hadoop(十四):HDFS的高可用机制

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 HDFS的高可用机制 HDFS高可用介绍 组件介绍 Nam ...

  10. 2015 UESTC Winter Training #10【Northeastern Europe 2009】

    2015 UESTC Winter Training #10 Northeastern Europe 2009 最近集训都不在状态啊,嘛,上午一直在练车,比赛时也是刚吃过午饭,状态不好也难免,下次比赛 ...

最新文章

  1. python项目中无法import不同文件的代码
  2. WINCE6.0+S3C2443下的usb function(功能)驱动
  3. 4.6 explain 之 rows
  4. 计算机基础- -认识磁盘
  5. python每行输出14个数_python – 计算pandas中每行的一些值的列数
  6. Imgproc.findContours函数
  7. javajs ---- 判断字符串中是否包含子串
  8. kafka 的structured stream 总结
  9. spark2.1.0之源码分析——RPC客户端工厂TransportClientFactory
  10. 例2.4 Day of Week - 九度教程第7题(日期类问题)
  11. 计算机怎么删除表格,怎么快速删除电脑word文档中不想要的表格
  12. 淘宝sign 解密 淘宝商品爬虫
  13. 诗经 - 小雅 -采薇
  14. 睡觉、吃饭、打豆豆。
  15. 【FCN】Fully Convolutional Networks for Semantic Segmentation学习
  16. 阿里云ECS重置实例密码
  17. 华为k662c的虚拟服务器,华为k662c路由器怎么设置 | 华为k662c路由器设置_什么值得买...
  18. win10系统安装到服务器失败怎么解决,windows10安装失败怎么办?解决win10安装失败的方法教程[多图]...
  19. C语言逗号表达式赋值、野指针成因、用户标识符、字符串赋值的几个概念
  20. ios 渐变透明背景_渐变色彩的室内应用技巧

热门文章

  1. 【Linux】文件及目录
  2. oracle的多个exclude,记录一下expdp exclude的用法
  3. flashgot免费下载音乐
  4. 普林斯顿邓嘉学生亲述:一定要博士学位?不,我本科生也能在大厂当应用科学家...
  5. 阿里架构大牛说:JVM从入门到入魔,就是这么简单
  6. 倒不过的“饮食时差”,减肥路上的最大阻碍?
  7. 6大页面数据抓取工具
  8. “反悔”贪心 烤鸡翅
  9. 国内各大企业邮箱,选择看重哪几个方面?
  10. IDEA插件系列(105):IDEA Mind Map插件——IDEA思维导图