提高十连测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

不难发现对于⼀个询问,值⼩于等于某个值的所有位置可以由⼀些⾏和列的并表示出。联通分为⼏种情况。

  1. 井字型联通,即有⼀⾏通过第⼀个位置,有⼀列通过第⼆个位置或反过来。答案为曼哈顿距离。
  2. Z字型联通,即两个位置都有⾏通过,并且有⾄少⼀个列。若列在两个位置之间则答案就是曼哈顿距离,否则需要找到最靠近中间的列来计算距离。
  3. 两个位置之间的所有⾏或所有列都出现。答案为曼哈顿距离。

若我们对⾏和列维护⼀个数组,数组中的值为最后⼀次被清空的时间,那么对于⼀个询问,这个⾏或列在询问中出现当且仅当它的值⼤于等于某个数。我们只需要维护两个操作:找到在 $ 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的更多相关文章

  1. ZROI 提高十连测 DAY3

    由于我不太会写 觉得从比赛开始就冷静分析.然后看完三道题心态有点爆炸没有紧扣题目的性质. 这个心态是不可取的尽量不要有畏难心理 不要草草的写暴力. LINK:[最长01子序列](http://zhen ...

  2. ZROI2019 提高十连测

    额 掰手指头一数 特么又是第三年十连测了= = 2017一场没打 那时候好像一场比赛也就100人左右 2018前几场还都好好补了 后来开始放飞自我了 这时候一场有150人还多了 2019想让今年的No ...

  3. ZROI 提高十连测 Day1

    第一天的提高模拟测 考前特意睡了20min 还是歇菜了,果然自己菜是真实的. 题目质量海星 但是我都不会这是真的...题目由于是花钱买的这里就不放了 LINK:problem 熟悉我的人应该都知道账号 ...

  4. ZROI 提高十连测 DAY2

    总结:入题尽量快,想到做法要先证明是否正确是否有不合法的情况,是否和题目中描述的情景一模一样.    不要慌 反正慌也拿不了多少分,多分析题目的性质如果不把题目的性质分析出来的话,暴力也非常的难写,有 ...

  5. bzoj 5216 [Lydsy2017省队十连测]公路建设 线段树维护 最小生成树

    [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 93  Solved: 53[Submit][Status][ ...

  6. bzoj 5216: [Lydsy2017省队十连测]公路建设

    5216: [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 66  Solved: 37[Submit][St ...

  7. Lydsy2017省队十连测

    5215: [Lydsy2017省队十连测]商店购物 可能FFT学傻了,第一反应是前面300*300背包,后面FFT... 实际上前面背包,后面组合数即可.只是这是一道卡常题,需要注意常数.. //A ...

  8. 正睿 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( ...

  9. 正睿 2018 提高组十连测 Day2 T2 B

    题目链接 http://www.zhengruioi.com/contest/84/problem/318 题解写的比较清楚,直接扒过来了. B 算法 1 直接按题意枚举,动态规划或是记忆化搜索. 时 ...

随机推荐

  1. 一、Windows docker入门篇

    win7.win8 等需要利用 docker toolbox 来安装,国内可以使用阿里云的镜像来下载,下载地址:http://mirrors.aliyun.com/docker-toolbox/win ...

  2. 数据多的时候为什么要使用redis而不用mysql?

    2018-06-28  136465569...  转自 庆亮trj21bc... 修改   微信 分享: Redis和MySQL的应用场景是不同的. 通常来说,没有说用Redis就不用MySQL的这 ...

  3. 编写Postgres扩展之四:测试

    原文:http://big-elephants.com/2015-11/writing-postgres-extensions-part-iv/ 编译:http://big-elephants.com ...

  4. Sharding-JDBC介绍

    Sharding-JDBC是当当应用框架ddframe中,从关系型数据库模块dd-rdb中分离出来的数据库水平分片框架,实现透明化数据库分库分表访问.Sharding-JDBC是继dubbox和ela ...

  5. 自定义标签之inclusion_tag

    1.在当前app下创建templatetags文件夹 2.在templatetags文件夹下面创建自定义的mytag.py文件 3.在mytag.py文件中的代码 from django.templa ...

  6. nginx热加载、热升级、回滚

    修改完配置文件后使用 nginx -s reload 命令进行热加载 编译好新的 nginx 二进制文件后,运行nginx 开启nginx服务,然后使用 kill -USR2 新的nginx_mast ...

  7. SAP Marketing Cloud功能简述(一) : Contacts和Profiles

    Dong Grace是Jerry的同事,目前是SAP成都研究院数字创新空间团队的一名实习生,明年7月才毕业.这篇文章是Grace对SAP Marketing Cloud功能梳理的一篇学习笔记,因为篇幅 ...

  8. ELK文档-安装部署

    一.ELK简介 请参考:http://www.cnblogs.com/aresxin/p/8035137.html 二.ElasticSearch安装部署 请参考:http://blog.51cto. ...

  9. javascript_10-函数

    函数 //定义函数 0-100 相加 function getSum() { var sum = 0; for (let i = 1; i <= 100; i++) { sum += i; } ...

  10. windows 下 redis 的安装及使用

    1.下载及安装redis 下载地址:https://github.com/dmajkic/redis/downloads 找到对应的版本下载安装 打开cmd窗口,用cd命令进入到安装redis的根目录 ...