题解:CF1630B Range and Partition
非常妙的好题。
首先容易发现
然后我们需要发现一个结论:这个必要条件同时也是充分条件。
证明:我们令
接下来就简单了。我们找到一个长度为
bool check(int x){
for (int i=1;i+x<=n;i++){
int j=i+x;
int cnt=sum[j]-sum[i-1];
int la=n-cnt;
if (cnt-la>=k) return 1;
}
return 0;
}
struct node{
int x,id;
}b[N],dp[N];
void sol(){
cin>>n>>k;
for (int i=1;i<=n;i++) sum[i]=0;
for (int i=1;i<=n;i++) cin>>a[i],sum[a[i]]++;
for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
int L=0,R=n-1,Ans=0;
while (L<=R){
int mid=(L+R)>>1;
if (check(mid)) Ans=mid,R=mid-1;
else L=mid+1;
}// 二分找出 x 和 y
int l=0,r=0;
for (int i=1;i+Ans<=n;i++){
int j=i+Ans;
int cnt=sum[j]-sum[i-1];
int la=n-cnt;
if (cnt-la>=k){
l=i,r=j;
break;
}
}
cout<<l<<' '<<r<<endl;
for (int i=1;i<=n;i++){
if (l<=a[i]&&a[i]<=r) sum[i]=1;
else sum[i]=-1;
}
for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
int x=sum[n];
int m=0;
for (int i=1;i<=n;i++){
if (sum[i]<x&&sum[i]>0) b[++m]={sum[i],i};//把前面的小于 sum[n] 的数拿出来
}
int cnt=0;
for (int i=1;i<=m;i++){
if (dp[cnt].x<b[i].x) dp[++cnt]=b[i];
else{
int L=0,R=cnt+1,Ans=0;
while (L<=R){
int mid=(L+R)>>1;
if (dp[mid].x>=b[i].x) Ans=mid,R=mid-1;
else L=mid+1;
}
if (b[i].x<dp[Ans].x) dp[Ans]=b[i];
}
}//求 LIS
vector<int> ans;
for (int i=1;i<k;i++) ans.pb(dp[i].id);
ans.pb(n);
int la=1;
for (int x:ans){
cout<<la<<' '<<x<<endl;
la=x+1;
}
}