提高十连测day3
提高十连测day3
A
我们可以枚举两个 $ 1 $ 之间的相隔距离,然后计算形如 $ 00100100 \cdots $ 的串在原串中最⻓⼦序列匹配即可,复杂度 $ O(n^2) $ 。寻找 $ S $ 在 $ T $ 中的最⻓⼦序列匹配直接贪⼼的扫⼀遍就⾏了。
我们可以考虑优化这个过程,快速匹配连续的 $ 0 $ 。只要⼆分找出下⼀个 的匹配位置即可。
由于 $ 1 $ 的个数为调和级数 ,所以总复杂度 $ O(n \log n) $ 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
const int N = 1e5 + 100;
int cnt,len,ans;
int sum[N],num[N];
char ch[N];
inline int Find(int pos, int x) {
int l = pos, r = cnt;
int pre = cnt + 1;
while(l <= r) {
int mid = (l + r) >> 1;
if(sum[mid] >= x) {
pre = mid;
r = mid-1;
}
else l = mid + 1;
}
return pre;
}
inline void check(int x) {
int key = x, pos = 1, pre = 0;
while(true) {
pos = Find(pos, key);
if(pos == cnt) {
if(pre + x >= x * 2 + 1)
ans = max(pre + x, ans);
return;
}
if(pos == cnt + 1) {
if(pre >= x * 2 + 1)
ans = max(pre, ans);
return;
}
key = sum[pos] + x;
pre += x + 1;
}
return;
}
int main() {
scanf("%s", ch + 1);
len = strlen(ch + 1);
for(int i = 1 ; i <= len ; i++)
num[i] = ch[i] - '0';
num[++len] = 1;
int tmp = 0;
for(int i = 1 ; i <= len - 1 ; i++)
if(!num[i]) tmp = 0;
else {
tmp++;
ans = max(tmp, ans);
}
int now = 0;
for(int i = 1 ; i <= len ; i++) {
if(!num[i]) now++;
else sum[++cnt] = now;
}
for(int i = 1 ; i <= len ; i++) check(i);
printf("%d \n", ans);
//system("pause");
return 0;
}
B
我们⾸先可以想到朴素地将到达每个点的所有距离⽤背包记下来,可以获得 $ 40 $ 分,位运算优化背包可以获得 $ 60 $ 分。
但其实可以用 $ set $ 维护合法的路径,可以得 $ 60 $ 分。
接下来考虑我们并不需要到达⼀个点的所有距离。
我们考虑三个距离 $ x,y,z $ ,若 ,$ \frac{1}{11}z \leq x \leq y \leq z $ 那么 $ y $ 这个距离可以不⽤记。那么每个点只需要记录 $ \log $ 级别的距离。合并两个距离集合 $ A,B $ 时使⽤归并排序可以做到 $ O(\los M) $ 。
最终复杂度为 $ O(m \log M) $ 。其中 $ M $ 是值域。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
#define M 410
const int N = 2e5 + 100;
struct Edge {
int to,from;
int data;
}e[N * 2];
LL head[N],degree[N];
LL num[N],n,m,q,cnt;
LL dis[N][M],tmp[N];
queue<int> qu;
inline void add_edge(int x,int y,int z) {
e[++cnt].from = y;
e[cnt].data = z;
e[cnt].to = head[x];
head[x] = cnt;
degree[y]++;
}
void Find(int x,int y,int val) {
int l = 1,r = 1,now = 0;
while(l <= num[x] && r <= num[y]) {
LL u = dis[x][l] + val;
if(u < dis[y][r]) {
while(now >= 2 && u >= tmp[now] && (double)tmp[now - 1] > (double)u / 1.1) now--;
tmp[++now] = u;
l++;
} else {
while(now >= 2 && dis[y][r] >= tmp[now] && (double)tmp[now - 1] > (double)dis[y][r] / 1.1) now--;
tmp[++now] = dis[y][r];
r++;
}
}
while(l <= num[x]) {
LL u = dis[x][l] + val;
while(now >= 2 && u >= tmp[now] && (double)tmp[now - 1] > (double)u / 1.1) now--;
tmp[++now] = u;
l++;
}
while(r <= num[y]) {
while(now >= 2 && dis[y][r] >= tmp[now] && (double)tmp[now - 1] > (double)dis[y][r] / 1.1) now--;
tmp[++now] = dis[y][r];
r++;
}
num[y] = now;
for(int i = 1 ; i <= now ; i++)
dis[y][i] = tmp[i];
}
inline void prework() {
qu.push(1);
dis[1][++num[1]] = 0;
while(!qu.empty()) {
int u = qu.front();
qu.pop();
for(int i = head[u] ; i ; i = e[i].to) {
int v = e[i].from;
Find(u,v,e[i].data);
degree[v]--;
if(!degree[v]) qu.push(v);
}
}
}
int main() {
scanf("%lld%lld%lld",&n,&m,&q);
for(int i = 1 ; i <= m ; i++) {
LL x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
add_edge(x,y,z);
}
prework();
while(q--) {
LL disx,x;
scanf("%lld%lld",&x,&disx);
int pos = lower_bound(dis[x] + 1,dis[x] + num[x] + 1,disx) - dis[x];
if(pos == num[x] + 1) {
puts("NO");
continue;
}
if((double)dis[x][pos] <= (double)1.1 * disx) puts("YES");
else puts("NO");
}
//system("pause");
return 0;
}
C
不难发现对于⼀个询问,值⼩于等于某个值的所有位置可以由⼀些⾏和列的并表示出。联通分为⼏种情况。
- 井字型联通,即有⼀⾏通过第⼀个位置,有⼀列通过第⼆个位置或反过来。答案为曼哈顿距离。
- Z字型联通,即两个位置都有⾏通过,并且有⾄少⼀个列。若列在两个位置之间则答案就是曼哈顿距离,否则需要找到最靠近中间的列来计算距离。
- 两个位置之间的所有⾏或所有列都出现。答案为曼哈顿距离。
若我们对⾏和列维护⼀个数组,数组中的值为最后⼀次被清空的时间,那么对于⼀个询问,这个⾏或列在询问中出现当且仅当它的值⼤于等于某个数。我们只需要维护两个操作:找到在 $ x $ 位置后的第⼀个⼤于等于 $ v $ 的位置、找到在 $ x $ 位置前的最后⼀个⼤于等于 $ v $ 的位置。这两个操作可以⽤线段树上⼆分实现,时间复杂度 $ O(\log n) $ 。
对于第三种情况可能需要单独维护⼀个单点修改询问区间极值的线段树。
总复杂度 $ O(Q \log n) $ 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
#define lson x * 2
#define rson x * 2 + 1
const int N = 1e5 + 100;
struct Segment_Tree {
struct Tree {
int tag, minn, maxx;
}tree[N << 2];
void pushup(int x) {
tree[x].minn = min(tree[lson].minn, tree[rson].minn);
tree[x].maxx = max(tree[lson].maxx, tree[rson].maxx);
}
void build(int x, int l, int r) {
if(l == r) {
tree[x].minn = 0;
tree[x].maxx = 0;
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
pushup(x);
}
void pushdown(int x) {
if(tree[x].tag) {
tree[lson].minn += tree[x].tag;
tree[rson].minn += tree[x].tag;
tree[lson].maxx += tree[x].tag;
tree[rson].maxx += tree[x].tag;
tree[lson].tag += tree[x].tag;
tree[rson].tag += tree[x].tag;
tree[x].tag = 0;
}
}
void update(int x, int l, int r, int ll, int rr, int c) {
if(l == ll && r == rr) {
tree[x].tag += c;
tree[x].minn += c;
tree[x].maxx += c;
return;
}
pushdown(x);
int mid = (l + r) >> 1;
if(rr <= mid) update(lson, l, mid, ll, rr, c);
else if (ll > mid) update(rson, mid + 1, r, ll, rr, c);
else {
update(lson, l, mid, ll, mid, c);
update(rson, mid + 1, r, mid + 1, rr, c);
}
pushup(x);
}
void delet(int x, int l, int r, int v) {
if(l == r) {
tree[x].minn = 0;
tree[x].maxx = 0;
return;
}
pushdown(x);
int mid = (l + r) >> 1;
if(v <= mid) delet(lson, l, mid, v);
else delet(rson, mid + 1, r, v);
pushup(x);
}
int query(int x, int l, int r, int ll, int rr, int v) {
if(l == ll && r == rr) {
if(v == 1) return tree[x].minn;
else return tree[x].maxx;
}
pushdown(x);
int mid = (l + r) >> 1;
if(rr <= mid) return query(lson, l, mid, ll, rr, v);
else if(ll > mid) return query(rson, mid + 1, r, ll, rr, v);
else {
if(v == 1) return min(query(lson, l, mid, ll, mid, v), query(rson, mid + 1, r, mid + 1, rr, v));
else return max(query(lson, l, mid, ll, mid, v), query(rson, mid + 1, r, mid + 1, rr, v));
}
}
}line, row;
int n, m, q;
int find1(int x, int v) {
int l = 1, r = x-1, res = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(row.query(1, 1, m, mid, x-1, 1) <= v) {
res = mid;
l = mid + 1;
}
else r = mid-1;
}
return res;
}
int find2(int x, int v) {
int l = x + 1, r = m, res = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(row.query(1, 1, m, x + 1, mid, 1) <= v) {
res = mid;
r = mid-1;
}
else l = mid + 1;
}
return res;
}
int find3(int x, int v) {
int l = 1, r = x-1, res = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(line.query(1, 1, n, mid, x-1, 1) <= v) {
res = mid;
l = mid + 1;
}
else r = mid-1;
}
return res;
}
int find4(int x, int v) {
int l = x + 1, r = n, res = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(line.query(1, 1, n, x + 1, mid, 1) <= v) {
res = mid;
r = mid-1;
}
else l = mid + 1;
}
return res;
}
bool deal1(int a, int b, int c, int d, int v) {
if(a > c) swap(a, c);
if(line.query(1, 1, n, a, c, 2) <= v) return 1;
if(b > d) swap(b, d);
if(row.query(1, 1, m, b, d, 2) <= v) return 1;
return 0;
}
bool deal2(int a, int b, int c, int d, int v) {
int av = line.query(1, 1, n, a, a, 1);
int bv = row.query(1, 1, m, b, b, 1);
int cv = line.query(1, 1, n, c, c, 1);
int dv = row.query(1, 1, m, d, d, 1);
if(a == c && av <= v) return 1;
if(b == d && bv <= v) return 1;
if(av <= v && dv <= v) return 1;
if(bv <= v && cv <= v) return 1;
if(av <= v && cv <= v && row.query(1, 1, m, min(b, d), max(b, d), 1) <= v) return 1;
if(bv <= v && dv <= v && line.query(1, 1, n, min(a, c), max(a, c), 1) <= v) return 1;
return 0;
}
int deal3(int a, int b, int c, int d, int v) {
int res, mins = 2e9, dis = abs(a - c) + abs(b - d);
if(line.query(1, 1, n, a, a, 2) <= v && line.query(1, 1, n, c, c, 2) <= v) {
res = find1(min(b, d), v);
if(res != -1) mins = min(mins, dis + 2 * abs(res - min(b, d)));
res = find2(max(b, d), v);
if(res != -1) mins = min(mins, dis + 2 * abs(res - max(b, d)));
}
if(row.query(1, 1, n, b, b, 2) <= v && row.query(1, 1, n, d, d, 2) <= v) {
res = find3(min(a, c), v);
if(res != -1) mins = min(mins, dis + 2 * abs(res - min(a, c)));
res = find4(max(a, c), v);
if(res != -1) mins = min(mins, dis + 2 * abs(res - max(a, c)));
}
if(mins == 2e9) return-1;
else return mins;
}
int work() {
int a,b,c,d,v;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&v);
if(a == c && b == d) return 0;
if(deal1(a, b, c, d, v) || deal2(a, b, c, d, v))
return abs(a - c) + abs(b - d);
return deal3(a, b, c, d, v);
}
int main() {
scanf("%d%d%d",&n,&m,&q);
line.build(1, 1, n);
row.build(1, 1, m);
while (q--) {
line.update(1, 1, n, 1, n, 1);
row.update(1, 1, m, 1, m, 1);
int opt,x;;
scanf("%d",&opt);
if(opt == 1) {
scanf("%d",&x);
line.delet(1, 1, n, x);
}
if(opt == 2) {
scanf("%d",&x);
row.delet(1, 1, m, x);
}
if(opt == 3) printf("%d \n",work());
}
//system("pause");
return 0;
}
提高十连测day3的更多相关文章
- ZROI 提高十连测 DAY3
由于我不太会写 觉得从比赛开始就冷静分析.然后看完三道题心态有点爆炸没有紧扣题目的性质. 这个心态是不可取的尽量不要有畏难心理 不要草草的写暴力. LINK:[最长01子序列](http://zhen ...
- ZROI2019 提高十连测
额 掰手指头一数 特么又是第三年十连测了= = 2017一场没打 那时候好像一场比赛也就100人左右 2018前几场还都好好补了 后来开始放飞自我了 这时候一场有150人还多了 2019想让今年的No ...
- ZROI 提高十连测 Day1
第一天的提高模拟测 考前特意睡了20min 还是歇菜了,果然自己菜是真实的. 题目质量海星 但是我都不会这是真的...题目由于是花钱买的这里就不放了 LINK:problem 熟悉我的人应该都知道账号 ...
- ZROI 提高十连测 DAY2
总结:入题尽量快,想到做法要先证明是否正确是否有不合法的情况,是否和题目中描述的情景一模一样. 不要慌 反正慌也拿不了多少分,多分析题目的性质如果不把题目的性质分析出来的话,暴力也非常的难写,有 ...
- bzoj 5216 [Lydsy2017省队十连测]公路建设 线段树维护 最小生成树
[Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 93 Solved: 53[Submit][Status][ ...
- bzoj 5216: [Lydsy2017省队十连测]公路建设
5216: [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 66 Solved: 37[Submit][St ...
- Lydsy2017省队十连测
5215: [Lydsy2017省队十连测]商店购物 可能FFT学傻了,第一反应是前面300*300背包,后面FFT... 实际上前面背包,后面组合数即可.只是这是一道卡常题,需要注意常数.. //A ...
- 正睿 2018 提高组十连测 Day4 T3 碳
记'1'为+1,'0'为-1; 可以发现 pre[i],suf[i]分别为前/后缀和 a[i]=max(pre[l.....i]); b[i]=max(suf[i+1....r]); ans=max( ...
- 正睿 2018 提高组十连测 Day2 T2 B
题目链接 http://www.zhengruioi.com/contest/84/problem/318 题解写的比较清楚,直接扒过来了. B 算法 1 直接按题意枚举,动态规划或是记忆化搜索. 时 ...
随机推荐
- Jenkins 发邮件的Job
Jenkins要做到构建失败的时候发送邮件,常规做法是加个全局的post failure,类似这样的代码 pipeline { agent any stages { stage('deploy') { ...
- synchronize与lock
1. synchronize的作用 synchronize是java最原始的同步关键字,通过对方法或者代码块进行加锁实现对临界区域的保护.线程每次进去同步方法或者代码块都需要申请锁,如果锁被占用则会等 ...
- centos iptables 数据转发
iptables -t nat -I PREROUTING -p tcp --dport 3389 -j DNAT --to 38.X25.X.X02 iptables -t nat -I POSTR ...
- 【转载】linux如何将新硬盘挂载到home目录下
举例说明: 新增磁盘的设备文件名为 /dev/vdb 大小为100GB. #fdisk -l 查看新增的的磁盘 1.对新增磁盘进行分区 #fdisk /dev/vdb 按提示操作 p打印 n新增 d ...
- Tensorflow&CNN:验证集预测与模型评价
版权声明:本文为博主原创文章,转载 请注明出处:https://blog.csdn.net/sc2079/article/details/90480140 - 写在前面 本科毕业设计终于告一段落了.特 ...
- Java程序员完美设置,Mac编程指南
重装了不知道多少次Windows,Linux发行版换来换去总是觉得不满意,终于下定决心在年头买了人生中第一台Mac. 为什么是Mac 现在的移动端.服务器端跑的大多数都是Unix系统,熟悉Un ...
- 模仿DotnetCore中间件的方式,做一个列表过滤的功能
我们的很多功能当中都会遇到对版本进行过滤的场合,例如你可能需要对列表中的数据的时间进行过滤.版本过滤.渠道以及地区信息进行过滤. 原本的做法:设计很多个过滤方法,通过枚举的方式组合,选择需要过滤哪些方 ...
- JDBC终章- 使用 DBUtils实现增删查改- C3P0Utils数据源/QueryRunner runner连接数据源并执行sql
JDBC终章- 使用 DBUtils实现增删查改 1.数据库结构 Create Table CREATE TABLE `user` ( `id` ) NOT NULL AUTO_INCREMENT, ...
- centos中python2.7被覆盖,yum,python重新安装
参考如下,问题以解决,绝对有效 下载链接yum和python2.7网盘 链接:https://pan.baidu.com/s/1sC2crFW1I8F7zndJU0jjcA 提取码:5kia 直接参考 ...
- 《Hello--world团队》第三次作业:团队项目的原型设计
项目 内容 这个作业属于哪个课程 2016级计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 实验七 团队作业3:团队项目原型设计与开发 团队名称 <hello--world团 ...