Codeforces 193D Two Segments 解题报告
先是在蓝桥杯的网站上看到一道题:
给出1~n的一个排列,求出区间内所有数是连续自然数的区间的个数。n<=50000。
由于数据较弱,即使用O(N^2)的算法也能拿到满分。
于是在CF上发现了这一题:
给一个1~n的排列,在这个排列中选出两段区间,求使选出的元素排序后构成公差为1的等差数列的方案数。选出的两段区间中元素构成的集合相同时视为同一种方案。N<=300000。
可以发现CF的这题是上一题的强化版。
虽然蓝桥的题目是简化版,但正确的做法似乎没有CF这道题容易想到。
蓝桥的题首先想到的应该是枚举区间,判断区间最大值与最小值的差是否等于区间长度,这样时间复杂度是O(N^2)。
似乎不知道该如何优化。
因此先从CF这题考虑一个比较容易想到的做法:
考虑自然序列[l,r],假设已经知道[l,r]在读入序列中被分成了几段(假设f[l,r]=k),那么在加入数l-1时,只需判断l-1这个数是单独构成一段(f[l-1,r]=k+1),还是并入了其中一段(f[l-1,r]=k),或者连接了两段(f[l,r]=k-1).当k等于1或2时就可以累加答案.使用这样的方法同样只需要枚举区间左右端点就可以得到一个O(n^2)的算法.再进一步考虑自然序列[l,i],(l<=i<=n).假设t=l-1,在读入序列的左右分别是数x和y(假设x<y).那么对应的f[l-1,m] 中m对应的区间要进行相应的更新(+1,-1),这里可以用线段树来维护.和查询.如此只需要n到1循环l,可以在O(nlogn)的时间复杂度实现.
对于蓝桥杯的题,假设当前枚举的数是i令[l,r],为f[i,l~r]数值区间.线段树需要维护的东西有区间内最小值,区间内等于最小值的数的个数.CF题需要额外维护,等于区间最小值+1的数的个数.
蓝桥杯的代码:
#include <iostream>
#include <cstdio>
using namespace std;
#define lson x<<1
#define rson x<< 1 | 1
const int MAXN = ;
struct Segtree {
int l, r, val, add, tol;
} St[MAXN << ];
int p[MAXN], a[MAXN];
int n, ans;
void Build (int x, int l, int r) {
St[x].l = l, St[x].r = r;
St[x].tol = r - l + ;
if (l == r) return;
int mid = (l + r) >> ;
Build (lson, l, mid), Build (rson, mid + , r);
}
void push (int x) {
if (St[x].add == ) return;
St[lson].add +=St[x].add, St[rson].add += St[x].add;
St[lson].val += St[x].add, St[rson].val += St[x].add;
St[x].add = ;
}
void update (int x) {
St[x].val = min (St[lson].val, St[rson].val);
St[x].tol = St[lson].tol * (St[x].val == St[lson].val) + St[rson].tol * (St[x].val == St[rson].val);
}
void Modify (int x, int l, int r, int key) {
if (St[x].l >= l && St[x].r <= r) {
St[x].val += key, St[x].add += key;
return;
}
push (x);
int mid = (St[x].l + St[x].r) >> ;
if (mid >= l) Modify (lson, l, r, key);
if (mid < r) Modify (rson, l, r, key);
update (x);
}
void Query (int x, int l, int r) {
if (St[x].l >= l && St[x].r <= r) {
ans += St[x].tol * (St[x].val == );
return;
}
push (x);
int mid = (St[x].l + St[x].r) >> ;
if (mid >= l) Query (lson, l, r);
if (mid < r) Query (rson, l, r);
}
int main() {
scanf ("%d", &n);
for (int i = , x; i <= n; i++) {
scanf ("%d", &x);
p[x] = i;
}
Build (, , n);
for (int i = n; i; i--) {
a[p[i]] = i;
int x = a[p[i] - ], y = a[p[i] + ];
if (x > y) swap (x, y);
if (x && y) Modify (, i, x - , ), Modify (, y, n, -);
else if (y) Modify (, i, y - , );
else Modify (, i, n, );
Query (, i, n);
}
printf ("%d", ans);
}
CF的代码:
#include <iostream>
#include <cstdio>
using namespace std;
#define lson x<<1
#define rson x<< 1 | 1
const int MAXN = ;
struct Segtree {
int l, r, val, add, tol, tol2;
} St[MAXN << ];
int p[MAXN], a[MAXN];
int n;
long long ans;
void Build (int x, int l, int r) {
St[x].l = l, St[x].r = r;
St[x].tol = r - l + ;
if (l == r) return;
int mid = (l + r) >> ;
Build (lson, l, mid), Build (rson, mid + , r);
}
void push (int x) {
if (St[x].add == ) return;
St[lson].add +=St[x].add, St[rson].add += St[x].add;
St[lson].val += St[x].add, St[rson].val += St[x].add;
St[x].add = ;
}
void update (int x) {
St[x].val = min (St[lson].val, St[rson].val);
St[x].tol = St[lson].tol * (St[x].val == St[lson].val) + St[rson].tol * (St[x].val == St[rson].val);
St[x].tol2=St[lson].tol*(St[x].val+==St[lson].val)+St[rson].tol*(St[x].val+==St[rson].val);
St[x].tol2+=St[lson].tol2*(St[x].val==St[lson].val)+St[rson].tol2*(St[x].val==St[rson].val);
}
void Modify (int x, int l, int r, int key) {
if (St[x].l >= l && St[x].r <= r) {
St[x].val += key, St[x].add += key;
return;
}
push (x);
int mid = (St[x].l + St[x].r) >> ;
if (mid >= l) Modify (lson, l, r, key);
if (mid < r) Modify (rson, l, r, key);
update (x);
}
void Query (int x, int l, int r) {
if (St[x].l >= l && St[x].r <= r) {
ans += St[x].tol * (St[x].val <=)+St[x].tol2*(St[x].val==);
return;
}
push (x);
int mid = (St[x].l + St[x].r) >> ;
if (mid >= l) Query (lson, l, r);
if (mid < r) Query (rson, l, r);
}
int main() {
scanf ("%d", &n);
for (int i = , x; i <= n; i++) {
scanf ("%d", &x);
p[x] = i;
}
Build (, , n);
for (int i = n; i; i--) {
a[p[i]] = i;
int x = a[p[i] - ], y = a[p[i] + ];
if (x > y) swap (x, y);
if (x) Modify (, i, x - , ), Modify (, y, n, -);
else if (y) Modify (, i, y - , );
else Modify (, i, n, );
Query (, i, n);
}
printf ("%I64d", ans-n);
}
Codeforces 193D Two Segments 解题报告的更多相关文章
- Codeforces Round 665 赛后解题报告(暂A-D)
Codeforces Round 665 赛后解题报告 A. Distance and Axis 我们设 \(B\) 点 坐标为 \(x(x\leq n)\).由题意我们知道 \[\mid(n-x)- ...
- Codeforces Round 662 赛后解题报告(A-E2)
Codeforces Round 662 赛后解题报告 梦幻开局到1400+的悲惨故事 A. Rainbow Dash, Fluttershy and Chess Coloring 这个题很简单,我们 ...
- Codeforces Round #277.5 解题报告
又熬夜刷了cf,今天比正常多一题.比赛还没完但我知道F过不了了,一个半小时贡献给F还是没过--应该也没人Hack.写写解题报告吧= =. 解题报告例如以下: A题:选择排序直接搞,由于不要求最优交换次 ...
- codeforces B. Simple Molecules 解题报告
题目链接:http://codeforces.com/problemset/problem/344/B 题目意思:这句话是解题的关键: The number of bonds of an atom i ...
- codeforces 591A. Wizards' Duel 解题报告
题目链接:http://codeforces.com/problemset/problem/591/A 题目意思:其实看下面这幅图就知道题意了,就是Harry 和 He-Who-Must-Not-Be ...
- codeforces 582A. GCD Table 解题报告
题目链接:http://codeforces.com/problemset/problem/582/A 网上很多题解,就不说了,直接贴代码= = 官方题解: http://codeforces.com ...
- codeforces 581C. Developing Skills 解题报告
题目链接:http://codeforces.com/problemset/problem/581/C 题目意思:给出 n 个数:a1, a2, ..., an (0 ≤ ai ≤ 100).给出值 ...
- codeforces 577B. Modulo Sum 解题报告
题目链接:http://codeforces.com/problemset/problem/577/B 题目意思:就是给出 n 个数(a1, a2, ..., an) 和 m,问能不能从这 n 个数中 ...
- codeforces 540B.School Marks 解题报告
题目链接:http://codeforces.com/problemset/problem/540/B 题目意思:给出 k 个test的成绩,要凑剩下的 n-k个test的成绩,使得最终的n个test ...
随机推荐
- 传智播客C语言视频第一季(有效下载期为10.1-10.7,10.8关闭)
J:\传智播客_尹成_C语言从菜鸟到高手├─传智播客_尹成_C语言从菜鸟到高手_第一章C语言概述A│ 第一讲1.1C语言第一阶段.mp4│ 第二讲1.2c语言入门教程.mp4 ...
- 启动tomcat的 startup.bat屏幕一闪而过
有时启动tomcat 时,屏幕一闪而过,看不到是那里有问题.要想让屏幕停下来,做法如下: 1.打开 startup.bat 文件,在文件最后加上最后加一行@pause 2.重新运行 startup.b ...
- rspec学习02
元数据 RSpec-core存储元数据哈希每实例和组,其中包含他们的描述,声明的位置等等,这个hash控制很多RSpec核心的功能,包括输出格式化程序(访问描述和位置),和before,after钩子 ...
- Sicily1020-大数求余算法及优化
Github最终优化代码: https://github.com/laiy/Datastructure-Algorithm/blob/master/sicily/1020.c 题目如下: 1020. ...
- php中传值与传引用的区别。什么时候传值什么时候传引用?
值传递: 函数范围内对值的任何改变在函数外部都会被忽略; 引用传递: 函数范围内对值的任何改变在函数外部也能反映出这些修改: 优缺点:按值传递时,php必须复制值.特别是对于大型的字符串和对象来说 ...
- XSS 简单理解
什么是XSS? XSS(Cross Site Scripting),即跨站脚本攻击,是一种常见于web application中的计算机安全漏洞.XSS通过在用户端注入恶意的可运行脚本,若服务器端对用 ...
- UVa1628 UVaLive5847 Pizza Delivery
填坑系列(p.302) 既然不知道后面还要卖多少个就加一维状态嘛.. lrj写的O(n)转移?其实转移可以O(1) 貌似按x排序有奇效? #include<cstdio> #include ...
- 传统IO与NIO的比较
本文并非Java.io或Java.nio的使用手册,也不是如何使用Java.io与Java.nio的技术文档.这里只是尝试比较这两个包,用最简单的方式突出它们的区别和各自的特性.Java.nio提出了 ...
- 【Android - 框架】之Dagger2+MVP的用法
MVP模式本身相比于MVC模式就已经把View层和Controller层从Activity中进行了分离,将Model层和View层用Presenter层隔开,实现了初步的解耦.如果再加入Dagger2 ...
- 深入了解VSTS的Unit Test测试属性
深入的了解一下方法上带有的属性的含义.每个方法上几乎都带有TestMethod这个属性,我们直觉告诉我们,这肯定是表示被测试函数的意思.事实也正是如此,在Unit Test里,有许多测试属性,常用的如 ...