【題解】鑽石收藏家
有splay的標籤
其實用two-pointer就能輕鬆搞定
時間複雜度為O(n)
我們可以發現,將資料答案一定是資料的某兩個區間的長度和。對於判斷一個區間是否能夠被放到一個架子上,只需要判斷這個區間的首尾資料的差是否超過了k。 這裡,我們可以用兩個two-pointer來線性列舉區間,最後列舉這兩個區間之間的分割點來更新答案。
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<vector>
using namespace std;
int n,k,a[51000],l[51000],r[51000],p1,p2,maxx;
int mysort(int a,int b) {return a < b;}
void two_pointer()
{
p1 = 0;
p2 = 1;
for(int i = 1; i <= n; i++)
{
p1 ++;
while(a[p2] - a[p1] <= k && p2 < n) p2 ++;
if(a[p2] - a[p1] > k) p2 -- ;
l[p1] = p2 - p1 + 1;
}
for(int i = n-1; i > 0; i--) l[i] = max(l[i], l[i + 1]); //使用右側的最優解更新當前節點
}void tow_pointer()
{
p1 = n + 1;
p2 = n;
for(int i = 1; i <= n; i++)
{
p1 --;
while(a[p1] - a[p2] <= k && p2 > 1) p2 --;
if(a[p1] - a[p2] > k) p2 ++;
r[p1] = p1 - p2 + 1;
}for(int i = 2; i <= n; i++) r[i] = max(r[i], r[i - 1]);//使用右側的最優解更新當前節點
}
int main()
{
scanf("%d%d",&n,&k);
for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
sort(a+1,a+n+1,mysort);
two_pointer(); //列舉分割點右側的區間
tow_pointer(); //列舉分割點左側的區間
for(int i = 1; i < n; i++)
maxx = max(maxx, l[i + 1] + r[i]); //列舉分界點更新答案
cout << maxx;
return 0;
}