Codeforces Round #333 (Div. 2) B. Approximating a Constant Range st 二分
B. Approximating a Constant Range
Time Limit: 20 Sec
Memory Limit: 256 MB
题目连接
http://codeforces.com/contest/602/problem/B
Description
When Xellos was doing a practice course in university, he once had to measure the intensity of an effect that slowly approached equilibrium. A good way to determine the equilibrium intensity would be choosing a sufficiently large number of consecutive data points that seems as constant as possible and taking their average. Of course, with the usual sizes of data, it's nothing challenging — but why not make a similar programming contest problem while we're at it?
You're given a sequence of n data points a1, ..., an. There aren't any big jumps between consecutive data points — for each 1 ≤ i < n, it's guaranteed that |ai + 1 - ai| ≤ 1.
A range [l, r] of data points is said to be almost constant if the difference between the largest and the smallest value in that range is at most 1. Formally, let M be the maximum and m the minimum value of ai for l ≤ i ≤ r; the range [l, r] is almost constant if M - m ≤ 1.
Find the length of the longest almost constant range.
Input
The first line of the input contains a single integer n (2 ≤ n ≤ 100 000) — the number of data points.
The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 100 000).
Output
Print a single number — the maximum length of an almost constant range of the given sequence.
Sample Input
5
1 2 3 3 2
Sample Output
4
HINT
题意
给你n个数,要求你找到最长的区间,使得这个区间的最大值减去最小值之差的绝对值小于等于1
题解:
枚举每一个数,以这个数为这个区间的最小值,能够往左边延伸多少,往右边延伸多少
再枚举每一个数,以这个数为区间的最大值,能够往左边延伸多少,往右边延伸多少就好了
可以O(n) 也可以 像我一样 用倍增然后二分去找
代码:
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; #define maxn 100005 int n; int dp[maxn][20]; int dp1[maxn][20]; int a[maxn]; int L[maxn],R[maxn]; int mm[maxn]; void initrmp(int n) { mm[0]=-1; for(int i=1;i<=n;i++) { mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; dp[i][0]=a[i]; dp1[i][0]=a[i]; } for(int j = 1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); for(int j = 1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp1[i][j]=min(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]); } int queryMax(int l,int r) { int k = mm[r-l+1]; return max(dp[l][k],dp[r-(1<<k)+1][k]); } int queryMin(int l,int r) { int k = mm[r-l+1]; return min(dp1[l][k],dp1[r-(1<<k)+1][k]); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int Ans = 0; initrmp(n); for(int i=1;i<=n;i++) { int l=1,r=i; while(l<=r) { int mid = (l+r)/2; if(abs(a[i]-queryMin(mid,i))<=0 && abs(a[i]-queryMax(mid,i))<=1)r=mid-1; else l=mid+1; } L[i]=l; l=i,r=n; while(l<=r) { int mid = (l+r)/2; if(abs(a[i]-queryMin(i,mid))<=0 && abs(a[i]-queryMax(i,mid))<=1)l=mid+1; else r=mid-1; } R[i]=l-1; } for(int i=1;i<=n;i++) Ans = max(Ans,R[i]-L[i]+1); for(int i=1;i<=n;i++) { int l=1,r=i; while(l<=r) { int mid = (l+r)/2; if(abs(a[i]-queryMin(mid,i))<=1 && abs(a[i]-queryMax(mid,i))<=0)r=mid-1; else l=mid+1; } L[i]=l; l=i,r=n; while(l<=r) { int mid = (l+r)/2; if(abs(a[i]-queryMin(i,mid))<=1 && abs(a[i]-queryMax(i,mid))<=0)l=mid+1; else r=mid-1; } R[i]=l-1; } for(int i=1;i<=n;i++) Ans = max(Ans,R[i]-L[i]+1); cout<<Ans<<endl; }