BZOJ2096: [Poi2010]Pilots
2096: [Poi2010]Pilots
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 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
5 1 3 5 8 6 6 9 10
Sample Output
4
(有两个子串的长度为4: 5, 8, 6, 6 和8, 6, 6, 9.最长子串的长度就是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\n",ans); 52 return 0; 53 }