数列问题(二分+思维)好题
2017-10-18 19:47
288 查看
二分+思维好题
Description
有两个数列a,b,求有多少个区间[l,r]使得maxri=lai=minri=lbiInput
第一行为一个整数 n.第二行有 n 个整数,表示 a[1]……a
.
第三行有 n 个整数,表示 b[1]……b
.
Output
输出一个整数,表示满足条件的区间数Sample Input
61 2 3 2 1 4
6 7 1 2 3 2
Sample Output
2Sample 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; }
相关文章推荐
- 折半法(二分)搜索有序数列元素下标及数组传参问题
- 洛谷P1962 计蒜课习题 fib数列问题之二 矩阵二分快速幂
- 【分治法】分治法与二分搜索,棋盘覆盖问题
- codeForces 535C.Tavas and Karafs(二分+思维)
- 思维体操:用c#简单实现按一定规则输出有序数列
- 问题 D: 二分递归快排(Qsort) [2*]
- 二分查找,背包问题v3
- [杂题 思维] 51nod1448 二染色问题
- Fibonacii数列,兔子问题
- 识别和分析事物问题的思维方法
- 【DP】最长不下降子序列问题(二分)
- 二分搜索问题详解(java)
- 【动规】【二分】划分数列
- HDU-4908(思维之贡献问题)
- 编程求解,输入两个整数n和m,从数列1,2,3,……n中随意取几个数,使其和等于m。要求将所有的可能组合列出来(背包问题求解)
- B God Create Math 思维问题
- 【BZOJ1052】【HAOI2007】覆盖问题 二分+深搜check
- 斐波那契数列的余数周期问题
- 3n+1数列问题
- C++面试题:循环数列问题