BZOJ 4582: [Usaco2016 Open]Diamond Collector
Descrirption
给你一个长度为 \(n\) 的序列,求将它分成两个序列后最多个数,每个序列最大值最小值不能超过 \(k\)
Sol
二分+DP.
排一下序,找出以这个点结尾和开始的位置.
这个玩意可以二分也可以用单调队列,随便搞啊...
然后统计答案就是枚举第二个序列的起点,然后往后扫的时候统计一下,第一个序列的最大长度就可以了.
Code
/************************************************************** Problem: 4582 User: BeiYu Language: C++ Result: Accepted Time:76 ms Memory:1876 kb ****************************************************************/ #include <cstdio> #include <algorithm> #include <iostream> using namespace std; const int N =50050; int n,k,ans; int a[N]; int f[N],g[N]; inline int in(int x=0){ scanf("%d",&x);return x; } int uppp(int x){// >= int l=1,r=n,mid; for(;l<=r;){ mid=(l+r)>>1; if(a[mid] < x) l=mid+1; else r=mid-1; }return l; } int lwww(int x){//<= int l=1,r=n,mid; for(;l<=r;){ mid=(l+r)>>1; if(a[mid] <= x) l=mid+1; else r=mid-1; }return r; } int main(){ n=in(),k=in(); for(int i=1;i<=n;i++) a[i]=in(); sort(a+1,a+n+1); for(int i=1;i<=n;i++){ f[i]=i-uppp(a[i]-k)+1; g[i]=lwww(a[i]+k)-i+1; } // for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl; // for(int i=1;i<=n;i++) cout<<f[i]<<" ";cout<<endl; // for(int i=1;i<=n;i++) cout<<g[i]<<" ";cout<<endl; for(int i=1;i<=n;i++){ ans=max(ans,f[i-1]+g[i]); f[i]=max(f[i],f[i-1]); } cout<<ans<<endl; return 0; }