Codeforces Round #768 D

D. Range and Partition

我们简化题意
将长度为n的数组a 分成k段 每一段中属于[x,y]的数的数量要大于不属于[x,y]的
我们可以直接二分区间[x,y] 我们钦定左端点 然后二分右端点即可
但是我们如何快速check这个区间是可行的
首先我们要分成k个区间 每个区间都要>0 我们假设每个就是1
那我们只需要check这个范围内的数是否大于等于不在这个范围的数+k即可
最后我们只需要按要求的 只要cnt=1 我们就输出一组解即可 因为每次cnt都按0开始 所以合法性显然

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 998244353;
const int mod = 998244353;
int up(int a,int b){return a<0?a/b:(a+b-1)/b;}
#define int long long
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#define YES cout<<"YES"<<endl;
#define NO cout<<"NO"<<endl;
#define _ 0
#define pi acos(-1)
#define INF 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int n,k,a[N],cot[N],pre[N];
bool check(int l,int r){return pre[r]-pre[l-1]>=(n-pre[r]+pre[l-1])+k;}
void solve() {
    cin>>n>>k;
    for(int i=1;i<=n;i++)cot[i]=pre[i]=0;
    for(int i=1;i<=n;i++)cin>>a[i],cot[a[i]]++;
    for(int i=1;i<=n;i++)pre[i]=pre[i-1]+cot[i];
    int l=0,r=INF;
    for(int i=1,j=1;j<=n;j++){
        while(i<=j&&check(i,j)){
            if(j-i<r-l){
                r=j;
                l=i;
            }
            i++;
        }
    }
    cout<<l<<' '<<r<<endl;
    int res=0;
    for(int i=1;i<=n;i++){
        int cnt=0;
        for(int j=i;j<=n;j++){
            if(res==k-1){
                cout<<i<<' '<<n<<endl;
                return;
            }
            if(l<=a[j]&&a[j]<=r)cnt++;
            else cnt--;
            if(cnt>0){
                res++;
                cout<<i<<' '<<j<<endl;
                i=j;
                break;
            }
        }
    }
}
signed main(){
    fast
    int T;cin>>T;
    while(T--) {
        solve();
    }
    return ~~(0^_^0);
}
posted @ 2022-10-03 20:04  ycllz  阅读(22)  评论(0)    收藏  举报