牛客NOIP暑期七天营-提高组1 解题报告
https://ac.nowcoder.com/acm/contest/920#question
A
构造+双指针
发现m的限制是1e5,而点数是5e4,所以不能构造太多的边,思考一下最短路树的定义。会发现其实就是要构造出一个最短路树。按\(a_i\)升序排序,那么只需要找一个在\(a_i-S\)的点连边即可。这个玩意可以直接用双指针或者二分或者其他什么数据结构来实现。判断无解即判断是否存在大于S的边或者0边。复杂度\(O(n \log n)\)
#include <bits/stdc++.h>
using namespace std;
namespace io {
char buf[1<<21], *p1 = buf, *p2 = buf;
inline char gc() {
if(p1 != p2) return *p1++;
p1 = buf;
p2 = p1 + fread(buf, 1, 1 << 21, stdin);
return p1 == p2 ? EOF : *p1++;
}
#define G gc
#ifndef ONLINE_JUDGE
#undef G
#define G getchar
#endif
template<class I>
inline void read(I &x) {
x = 0; I f = 1; char c = G();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = G(); }
x *= f;
}
template<class I>
inline void write(I x) {
if(x == 0) {putchar('0'); return;}
I tmp = x > 0 ? x : -x;
if(x < 0) putchar('-');
int cnt = 0;
while(tmp > 0) {
buf[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while(cnt > 0) putchar(buf[--cnt]);
}
#define in(x) read(x)
#define outn(x) write(x), putchar('\n')
#define out(x) write(x), putchar(' ')
} using namespace io;
#define ll long long
const int N = 100010;
int n, S, m;
struct Node {int v, id;} a[N];
struct edge {int u, v, w;} e[N];
bool operator < (Node a, Node b) {
return a.v < b.v;
}
int main() {
read(n); read(S);
for(int i = 1; i <= n; ++i) read(a[i].v), a[i].id = i;
sort(a + 1, a + n + 1);
bool flag = 0; int last = 1;
for(int i = 2; i <= n; ++i) {
if(a[i].v == 0) {flag = 1; break;}
while(last < i && a[i].v - a[last].v > S) ++last;
e[++m] = {a[last].id, a[i].id, a[i].v - a[last].v};
}
for(int i = 1; i <= m; ++i) if(e[i].w > S || e[i].w < 1) flag = 1;
if(flag) puts("-1");
else {
printf("%d\n", m);
for(int i = 1; i <= m; ++i) printf("%d %d %d\n", e[i].u, e[i].v, e[i].w);
}
return 0;
}
B
构造+贪心+01trie
因为是一个完全图,所以题目等价于,1到n的排列中,相邻两个数作为下标,\(a_i\)的\(xor\)最大值最小是多少。
因为高位对答案的影响更大,按位考虑,我们肯定需要让当前位为1的排在一块,为0的排在一块,那么答案的最大值一定在中间接壤点(因为这两部分内部再怎么xor也没这一位的一个1贡献大)。
所以找出有0也有1的最高位,然后将序列划分为两段。那么问题就变成了,在序列0和序列1中各选出一个数,使他们的xor和尽可能小。这个01Trie维护一下就好了。
赛时是写了一个同样思想的归并排序,但是没有想到“这两部分内部再怎么xor也没这一位的一个1贡献大”这一性质,所以写挂了...
#include <bits/stdc++.h>
using namespace std;
namespace io {
char buf[1<<21], *p1 = buf, *p2 = buf;
inline char gc() {
if(p1 != p2) return *p1++;
p1 = buf;
p2 = p1 + fread(buf, 1, 1 << 21, stdin);
return p1 == p2 ? EOF : *p1++;
}
#define G gc
#ifndef ONLINE_JUDGE
#undef G
#define G getchar
#endif
template<class I>
inline void read(I &x) {
x = 0; I f = 1; char c = G();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = G(); }
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = G(); }
x *= f;
}
template<class I>
inline void write(I x) {
if(x == 0) {putchar('0'); return;}
I tmp = x > 0 ? x : -x;
if(x < 0) putchar('-');
int cnt = 0;
while(tmp > 0) {
buf[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while(cnt > 0) putchar(buf[--cnt]);
}
#define in(x) read(x)
#define outn(x) write(x), putchar('\n')
#define out(x) write(x), putchar(' ')
} using namespace io;
#define ll long long
const int N = 1000100;
int n, t[N * 10][2], tot;
ll a[N], b[N][2];
void insert(ll x) {
int u = 0;
for(ll pos = 60; pos >= 0; --pos) {
int c = (x >> pos) & 1LL;
if(!t[u][c]) t[u][c] = ++tot;
u = t[u][c];
}
}
ll query(ll x) {
int u = 0; ll ans = 0;
for(ll pos = 60; pos >= 0; --pos) {
int c = (x >> pos) & 1LL;
if(t[u][c]) u = t[u][c];
else u = t[u][c ^ 1], ans += 1LL << pos;
}
return ans;
}
int main() {
read(n);
for(int i = 1; i <= n; ++i) read(a[i]);
int cnt[2];
for(ll pos = 60; pos >= 0; --pos) {
cnt[0] = cnt[1] = 0;
for(int i = 1; i <= n; ++i) {
int c = (a[i] >> pos) & 1;
b[++cnt[c]][c] = a[i];
}
if(cnt[0] && cnt[1]) break;
}
if(!cnt[0] || !cnt[1]) return puts("0"), 0;
for(int i = 1; i <= cnt[0]; ++i) insert(b[i][0]);
ll ans = 1LL << 61;
for(int i = 1; i <= cnt[1]; ++i) ans = min(ans, query(b[i][1]));
outn(ans);
}
C
最短路树+spfa
同起点到两个点的最短路的公共部分等价于该起点的最短路树上这两个点的lca到根的距离。字典序最小的话建最短路树的时候处理一下就好。将询问离线下来,每次处理出当前起点下的最短路树,然后对每个询问依次取max。这样就只用开一个最短路树的空间了。复杂度是O(nqlogn + nmk)(k为spfa中的那个常数)。正解是在建最短路树那里用Johnson算法,卡了spfa。因为过于码农所以没补这题= =记录了一下思想。
然后johnson算法的话,就是定义一个虚点,然后到每个点连长度为0的边,然后spfa一次跑出最短路,然后这个最短路就是每个节点的势能函数,记为h。那么将边权改为h[v]-h[u]+w,就能保证不存在负边权了,于是跑DIjkstra,最后将势能函数反推回去就可以得到最短路了。
这个玩意好像在rqy的Dijkstra跑费用流的课件里面看到过。
牛客NOIP暑期七天营-提高组1 解题报告的更多相关文章
- 牛客NOIP暑期七天营-普及组1 解题报告
A 对于\(100\%\),直接开个桶统计即可.入门题目. 代码:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=41 ...
- 牛客NOIP暑期七天营-提高组1
牛客NOIP暑期七天营-提高组1 链接 A 边权可为0就排序建一条链子. 但是边权不为0 除了第一个有0的不行. x连向上一个比他小的数. 期间判断有无解. #include <bits/std ...
- 牛客NOIP暑期七天营-提高组6
目录 A-积木大赛 题目描述 link 题解 代码 B-破碎的序列 题目描述 link 题解 C-分班问题 题目描述 link 题解 比赛链接 官方题解 A-积木大赛 题目描述 link 题解 标签: ...
- 牛客NOIP暑期七天营-提高组5+普及组5
————提高组———— 第一题:deco的abs 题目链接:https://ac.nowcoder.com/acm/contest/934/A 因为每个数都可以加任意次 d ,所以可以推出 0 < ...
- 牛客NOIP暑期七天营-提高组3
第一题:破碎的矩阵 题目链接:https://ac.nowcoder.com/acm/contest/932/A 刚看到这题的时候感觉特别熟悉...诶,这不就是codeforces某场比赛的某某 ...
- 牛客NOIP暑期七天营-提高组2
第一题:ACGT 题目链接:https://ac.nowcoder.com/acm/contest/931/A trie树.hash.map遍历 ①.trie树上的节点多记一个rest值表示还有多少 ...
- 牛客NOIP暑期七天营-提高组6C:分班问题 (组合数)
题意:A班有N个人,B班有M个人,现在要组成一个新的班级C班,为了公平,从AB班各抽相同人数的人. 现在求所有方案中,人数之和是多少. 思路:即求Σ k*C(N,k)*C(M,k); 先忽略这个 ...
- 牛客NOIP暑期七天营-提高组5
A:deco的abs. 水题,先%,然后相邻两个数min()一下差值. #include<bits/stdc++.h> #define ll long long using namespa ...
- 牛客NOIP暑期七天营-提高组2C:滑块(平衡树) (这里rope骗分)
A:hash 或者 map 或者trie. #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) usin ...
随机推荐
- 算法练习之x的平方根,爬楼梯,删除排序链表中的重复元素, 合并两个有序数组
1.x的平方根 java (1)直接使用函数 class Solution { public int mySqrt(int x) { int rs = 0; rs = (int)Math.sqrt(x ...
- vscode插件Power Mode
Power Mode官网 设置里添加 "powermode.enabled": true, "powermode.presets": "flames& ...
- sql 查找所有已经分配部门的员工
查找所有已经分配部门的员工的last_name和first_nameCREATE TABLE `dept_emp` (`emp_no` int(11) NOT NULL,`dept_no` char( ...
- java web中的相对路径和绝对路径
以往一直没注意javaweb中的相对路径和绝对路径问题,有时有问题了,才想起去看看是否是路径的问题,一直对路径问题都是一知半解.今天就姑且记录一下,毕竟事如春梦了无痕嘛,倘不记之笔墨,未免有辜彼苍之厚 ...
- [转]综述论文翻译:A Review on Deep Learning Techniques Applied to Semantic Segmentation
近期主要在学习语义分割相关方法,计划将arXiv上的这篇综述好好翻译下,目前已完成了一部分,但仅仅是尊重原文的直译,后续将继续完成剩余的部分,并对文中提及的多个方法给出自己的理解. _论文地址:htt ...
- Centos下Redis集群的搭建实现读写分离
Centos下Redis一主多从架构搭建 搭建目标:因为自己笔记本电脑配置较低的原因,模拟两台机器之间搭建一主一从的架构,主节点Redis主要用来写数据,数据写入到主节点的Redis,然后从节点就可以 ...
- Linux05 文件或目录的权限(ls、lsattr、chattr、chmod、chown、chgrp、file)
一.查看文件或目录的权限:ls -al 文件名/目录名 keshengtao@LAPTOP-F9AFU4OK:~$ ls -al total drwxr-xr-x keshengtao keshen ...
- python列表生成式、键盘输入及类型转换、字符串翻转、字母大小写、数组广播、循环语句等基础问题
Python知识总结 1.列表生成式 在实际开发过程中,当需要获取一个连续列表时,可直接使用range(3,10),但是如果获取该列表中每个数据的平方时,通常可以通过for循环来解决这个问题,如下 ...
- Numpy学习笔记(上篇)
目录 Numpy学习笔记(上篇) 一.Jupyter Notebook的基本使用 二.Jpuyter Notebook的魔法命令 1.%run 2.%timeit & %%timeit 3.% ...
- grafana部署安装
部署grafana 在prometheus& grafana server节点部署grafana服务. 1. 下载&安装 # 下载 [root@prometheus ~]# cd /u ...