您的位置:首页 > 其它

数列问题(二分+思维)好题

2017-10-18 19:47 288 查看

二分+思维好题

Description

有两个数列a,b,求有多少个区间[l,r]使得maxri=lai=minri=lbi

Input

第一行为一个整数 n.

第二行有 n 个整数,表示 a[1]……a
.

第三行有 n 个整数,表示 b[1]……b
.

Output

输出一个整数,表示满足条件的区间数

Sample Input

6

1 2 3 2 1 4

6 7 1 2 3 2

Sample Output

2

Sample Explaination

有两个区间满足条件,[4,4],[4,5]

Hint

我们分析,当区间长度l增大的时候,我们可选择的数更多,所以max(ai) 可能更大,min(ai)可能更小,也就是说对于任何左端点x,max(ai)和min(bi)满足单调性

我们更加深入的分析,即可发现对任意一个左端点x,有三种情况:

情况一



这种情况下一定存在L值满足条件,所以ans++

但仔细分析,两线一定只有一个交点吗?

不一定,因为L为一段区间的时候可能两值都相等,如图



这时我们就可以用二分处理

找出最小满足Lleft的和最大满足的Lright,然后ans+=Lright-Lleft+1

情况二



在这种情况下两值任具有单调性,具有相交的趋势,但是它们在maxlen之前没有相交,这种情况我们只能同情况一处理,即二分L,然后发现并求不出L的范围于是ans不改变

情况一和情况二都满足条件a[x]<b[x],在这种情况下我们可能可以通过扩展L使max(ai)变大而min(bi)变小从而期望在某一点达到相等

情况三



这种情况即a[x]>b[x],此时我们发现,扩展L只会使max(ai)变大min(bi)变小,两值会差的越来越多不可能相交,所以直接跳过就好了

Code

贴机房某大佬的AC代码…

#include<cstdio>
#include<cmath>
#include<algorithm>
#define redir(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)
using namespace std;
inline char gc(){
static char buf[1<<17],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<17,stdin),p1==p2)?EOF:*p1++;
}
template<class T>
inline void read(T&n){
register char ch=gc();
int sign=1;
for(n=0;(ch<'0'||ch>'9')&&ch!='-';ch=gc());
for(ch=='-'?ch=gc(),sign=-1:0;ch>='0'&&ch<='9';ch=gc()) n=(n<<1)+(n<<3)+ch-'0';
n*=sign;
}
const int N=200010;
int n;
int f
[21],g
[21];
inline void init(){
read(n);
for(register int i=1;i<=n;++i) read(f[i][0]);
for(register int i=1;i<=n;++i) read(g[i][0]);
f[++n][0]=2e9,g
[0]=-2e9;
for(register int i=1;i<21;++i)
for(register int j=1;j+(1<<i)-1<=n;++j)
f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]),
g[j][i]=min(g[j][i-1],g[j+(1<<(i-1))][i-1]);
}
inline int query1(int l,int r){
const int k=log2(r-l+1);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
inline int query2(int l,int r){
const int k=log2(r-l+1);
return min(g[l][k],g[r-(1<<k)+1][k]);
}
int main(){
redir("seq");
init();
register long long ans=0;
for(register int i=1;i<=n;++i){
if(f[i][0]>g[i][0]) continue;
register int l=i,r=n,mid,L=-1;
while(l<r){
mid=(l+r)>>1;
if(query1(i,mid)>=query2(i,mid)) r=mid,L=mid;
else l=mid+1;
}
if(L==-1) continue;
l=i,r=n;
register int R=i;
while(l<r){
mid=(l+r)>>1;
if(query1(i,mid)>query2(i,mid)) r=mid,R=mid;
else l=mid+1;
}
if(query1(i,l)>query2(i,l)) R=l;
ans+=(R-L);
}
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  题解 好题