51Nod 1810 连续区间
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1810
题目给出一个1~n的排列,问有多少连续区间。连续区间的定义为区间内元素排序后之间间隔为1。
对于一个区间[l,r],令mid=(l+r)/2,我们如果能在O(n)内求解出左端点在[l,mid],右端点在[mid+1,r]的连续区间数量,就可以将问题一分为二,递归求解[l,mid] [mid+1,r]。
现在来求解上面所说的这个子问题,首先默认i<j,有一个结论max[i~j]-min[i~j]==j-i时[i,j]是一个连续区间。所以我们维护两组从mid(mid+1)出发,向左(右)延伸的后(前)缀max和min数组。max[i~j]=max(max[i],max[j]),min同理。我们只要找到所有i,j组合使得结论式成立即可。
但是很明显朴素枚举是n^2的,我们能不能优化到n呢?
观察max[i~j],min[i~j],他们的来源有4种组合,因为是两两对应的,我们其中两个组合来讨论,另外两个可以同理推导。
第一种是max和min都来自mid左边。有max[i]-min[i]=j-i,推导得 j=max[i]-min[i]+i,只要枚举左半边的i,并判断j是否合法即可。
第二种是max来自左边min来自右边。有max[i]-min[j]=j-i,推导得max[i]+i=min[j]+j,枚举每个max[i]+i,计算有多少合法的j符合即可。说得轻松,这个j的数量怎么计算呢?
我们发现max想要来自左边,需要满足max[i]>max[j],同理min[i]>min[j]。同时我们发现从中心向外发散,max递增,min递减,也就是从中心向左枚举i的过程中max限制越来越宽松,min越来越严格。我们lp,rp来维护右半区间中满足当前i的[mid+1,r]的j的子窗口,可以预见的是随着i--,这个窗口会向右尺取。我们每加入一个j,就让一个计数数组中的cnt[min[j]+j]++,每剔除一个j则相应减减。对于每个i,完成尺取后,ans+=cnt[max[i]+i]。
对应搞定剩下两个情况后这题就理论AC了,剩下还有一些细节,比如l==r的处理,cnt数组的复原处理,输入挂优化什么的,搞搞就AC了。
#include <iostream>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstring>
#define LL long long
using namespace std;
const LL N = ;
int num[N],n;
LL ans;
int mx[N], mi[N];
int read() {
char ch;
for (ch = getchar(); ch<'' || ch>''; ch = getchar());
int x = ch - '';
for (ch = getchar(); ch >= ''&&ch <= ''; ch = getchar()) x = x * + ch - '';
return x;
}
void make_pre(LL l, LL r, LL mid)
{
mi[mid] = mx[mid] = num[mid];
mi[mid + ] = mx[mid + ] = num[mid + ];
for (int i = mid - ; i >= l; i--)
{
mx[i] = max(num[i], mx[i + ]);
mi[i] = min(num[i], mi[i + ]);
}
for (int i = mid + ; i <= r; i++)
{
mx[i] = max(num[i], mx[i - ]);
mi[i] = min(num[i], mi[i - ]);
}
}
struct tong
{
LL cnt[N * ];
void clear()
{
memset(cnt, , sizeof(cnt));
}
void setZero(LL num)
{
cnt[num + N] = ;
}
void add(LL num,int v)
{
cnt[num + N]+=v;
}
LL query(LL num)
{
return cnt[num+N];
}
}cnt; void solve(LL l, LL r)
{ int temp = ans;
LL mid = (l + r) /;
make_pre(l, r, mid);
//same i
for (int i = l; i <= mid; i++)
{
int nj = mx[i] - mi[i]+i;
if (nj>mid&&nj<=r&&mx[i]>mx[nj] && mi[i]<mi[nj]) ans++;
}
//same j
for (int i = mid+; i <= r; i++)
{
int nj = mx[i] - mi[i]-i;
nj = -nj;
if (nj<=mid&&nj>=l&&mx[i]>mx[nj] && mi[i]<mi[nj]) ans++;
}
//dif mx[i],mi[j]
LL pl = mid+,pr=mid+;
for (int i = mid; i>=l; i--)
{
while (pr <= r&&mx[pr] < mx[i])cnt.add(mi[pr] + pr,),pr++;
while (pl < pr&&mi[pl] > mi[i])cnt.add(mi[pl] + pl, -), pl++;
//if (cnt.query(mx[i] + i) < 0) cout << l << ' ' << r << ' ' << pl << endl;
ans += cnt.query(mx[i] + i);
}
while (pl < pr)cnt.setZero(mi[pl]+pl),pl++;
//dif mi[i],mx[j]
pl = mid , pr = mid;
for (int i=mid+; i<=r; i++)
{
while (pr >=l&&mx[pr] < mx[i])cnt.add(mi[pr] - pr, ), pr--;
while (pl > pr&&mi[pl] > mi[i])cnt.add(mi[pl] - pl, -), pl--;
//if(cnt.query(mx[i] - i)<0)cout << l << ' ' << r << ' ' << pl << endl;
ans += cnt.query(mx[i] - i);
}
while (pl > pr)cnt.setZero(mi[pl] - pl), pl--;
//cout << ans - temp << ' ' << l << ' ' << r << endl;
if (l == r)return;
solve(l, mid);
solve(mid + , r);
}
int main()
{
//cin.sync_with_stdio(false);
n = read();
for (int i = ; i < n; i++)num[i]=read();
ans = ;
cnt.clear();
solve(, n - );
printf("%lld\n", ans+n); return ;
}
51Nod 1810 连续区间的更多相关文章
- 51NOD 1810 连续区间 分治 区间计数
1810 连续区间 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 80 区间内所有元素排序后,任意相邻两个元素值差为1的区间称为“连续区间” 如:3,1,2是连续区间,但3, ...
- 51nod 1094 和为k的连续区间【前缀和/区间差/map】
1094 和为k的连续区间 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 收藏 关注 一整数数列a1, a2, ... , an(有正有负),以及另一个整数k ...
- 51Nod 1094 和为k的连续区间 | 水
Input示例 6 10 1 2 3 4 5 6 Output示例 1 4 #include "cstdio" #include "algorithm" #in ...
- 51Nod 1094 和为k的连续区间
#include <iostream> #include <algorithm> #include <cstring> using namespace std; t ...
- 51Nod 和为k的连续区间
一整数数列a1, a2, ... , an(有正有负),以及另一个整数k,求一个区间[i, j],(1 <= i <= j <= n),使得a[i] + ... + a[j] = k ...
- 【51Nod 1244】莫比乌斯函数之和
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1244 模板题... 杜教筛和基于质因子分解的筛法都写了一下模板. 杜教筛 ...
- 51Nod 1268 和为K的组合
51Nod 1268 和为K的组合 1268 和为K的组合 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 给出N个正整数组成的数组A,求能否从中选出若干个,使 ...
- 51Nod 1428 活动安排问题
51Nod 1428 活动安排问题 Link: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1428 1428 活 ...
- 51Nod 1278 相离的圆
51Nod 1278 相离的圆 Link: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1278 1278 相离的圆 基 ...
随机推荐
- 深度学习课程笔记(十三)深度强化学习 --- 策略梯度方法(Policy Gradient Methods)
深度学习课程笔记(十三)深度强化学习 --- 策略梯度方法(Policy Gradient Methods) 2018-07-17 16:50:12 Reference:https://www.you ...
- [HDU 2520] 我是菜鸟,我怕谁(不一样的for循环)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2520 //学学不一样的for循环 #include<iostream> #include& ...
- WEB安全学习二、注入工具 sqlmap的使用
使用的是Kali Linux 系统,系统中默认的sqlmap 是安装好了的,电脑上没有安装sqlmap,自己百度 ,需要python的环境 使用 命令 sqlmap -h 可以查看 sqlm ...
- 17秋 SDN课程 第三次上机作业
SDN 第三次上机作业 1.创建拓扑 2.利用OVS命令下发流表,实现vlan功能 3.利用OVS命令查看流表 s1: s2: 4.验证性测试 5.Wireshark 抓包验证
- Terminal run py文件
cd Documents cd PythonCode python3 hello.py Text Editor: Atom Atom 可以用来写 python 脚本 (文件后缀名 .py). 但是不用 ...
- 原生js总结
数据类型 基本类型值包括: undefined,null,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,它们的值保存在栈空间,我们通过按值来访问的. 引用类型包括 ...
- 利用JavaScriptSOAPClient直接调用webService --完整的前后台配置与调用示例
JavaScriptSoapClient下载地址:https://archive.codeplex.com/?p=javascriptsoapclient JavaScriptSoapClient的D ...
- 【Python】【电子邮箱】
#[[电子邮件]]'''Email的历史比Web还要久远,直到现在,Email也是互联网上应用非常广泛的服务. 几乎所有的编程语言都支持发送和接收电子邮件,但是,先等等,在我们开始编写代码之前,有必要 ...
- 【Java】【图形】
/* 栗子 了解swing */import javax.swing.*;public class test_swing extends JFrame { //继承JFrame顶层容器类(可以添加其他 ...
- ngui处理不规则按钮点击
吐个槽 棋牌类游戏做什么中国地图!!! 然后就要用到不规则按钮点击了 你懂的 213的unity虽然已经加入了polygoncollider 2d的支持 但是 但是 但是 是2d的 也就是说如果不 ...