BZOJ2096: [Poi2010]Pilots

2096: [Poi2010]Pilots

Time Limit: 30 Sec  Memory Limit: 162 MB
Submit: 270  Solved: 142
[Submit][Status]

Description

Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值。耍畸形一个人是不行的,于是他找到了你。

Input

输入:第一行两个有空格隔开的整数k(0<=k<=2000,000,000),n(1<=n<=3000,000),k代表Tz设定的最大值,n代表难度序列的长度。第二行为n个由空格隔开的整数ai(1<=ai<=2000,000,000),表示难度序列。

Output

输出:最大的字串长度。

Sample Input

3 9
5 1 3 5 8 6 6 9 10

Sample Output

4
(有两个子串的长度为4: 5, 8, 6, 6 和8, 6, 6, 9.最长子串的长度就是4)

HINT

 

Source

题解:
此题做的好艰辛,大神们都说是水题T_T
首先肯定是单调队列,然后我想的是枚举每一个可行区间的最小值,找出它向左向右更能拓展多少?
结果发现做不出来T_T
然后去膜拜wyx528的题解,发现我的思路就错了:
 

我们考虑顺序枚举序列的右端点 i,设在位置 i 处,取得最长合法序列的左端点为 L[i],易证随着 i 的增加
L[i]单调不减,于是开两个单调队列维护最大值和最小值即可,注意一下内存限制。时间复杂度 O(n)。

然后就是实现的问题了,首先必须先插入,然后不合题意的时候怎么删除呢?

yy了好久yy出了这样的操作:

1         f[i]=f[i-1];
2         while(a[q[0][l[0]]]-a[q[1][l[1]]]>k)
3           f[i]=q[0][l[0]]<q[1][l[1]]?q[0][l[0]++]+1:q[1][l[1]++]+1; 
4         ans=max(ans,i-f[i]+1);

f[i]代表着左区间端点。

注意各变量所代表的实际含义。

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<vector>
 8 #include<map>
 9 #include<set>
10 #include<queue>
11 #include<string>
12 #define inf 1000000000
13 #define maxn 3000005
14 #define maxm 500+100
15 #define eps 1e-10
16 #define ll long long
17 #define pa pair<int,int>
18 #define for0(i,n) for(int i=0;i<=(n);i++)
19 #define for1(i,n) for(int i=1;i<=(n);i++)
20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
22 #define mod 1000000007
23 using namespace std;
24 inline int read()
25 {
26     int x=0,f=1;char ch=getchar();
27     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
28     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 int n,k,l[2],r[2],a[maxn],f[maxn],q[2][maxn];
32 int main()
33 {
34     freopen("input.txt","r",stdin);
35     freopen("output.txt","w",stdout);
36     k=read();n=read();
37     for1(i,n)a[i]=read();
38     int ans=1;
39     l[0]=l[1]=1;f[0]=1;
40     for1(i,n)
41     {
42         while(l[0]<=r[0]&&a[q[0][r[0]]]<=a[i])r[0]--;
43         q[0][++r[0]]=i;
44         while(l[1]<=r[1]&&a[q[1][r[1]]]>=a[i])r[1]--;
45         q[1][++r[1]]=i;
46         f[i]=f[i-1];
47         while(a[q[0][l[0]]]-a[q[1][l[1]]]>k)
48           f[i]=q[0][l[0]]<q[1][l[1]]?q[0][l[0]++]+1:q[1][l[1]++]+1; 
49         ans=max(ans,i-f[i]+1);
50     }
51     printf("%d
",ans);
52     return 0;
53 }
View Code
原文地址:https://www.cnblogs.com/zyfzyf/p/4008295.html