Codeforces Round #768 (Div. 2) D. Range and Partition

题目链接

题意:

给定一个有n个整数的数组a,找到一个范围为[x,y] (x≤y)的值,并将a精确地分割成k个(1≤k≤n)子数组,如下所示:
    (1)每个子数组由a的几个连续元素组成,即对于某l和r(1≤l≤r≤n),它等于al,al+1,…,ar。
    (2)a中的每个元素都属于一个子数组。
    (3)在每个子数组中,范围[x,y] (包括) 内的元素数量严格大于范围外的元素数量。当且仅当x≤ai≤y时,索引为i的元素在[x,y]范围内。
打印任何最小化y−x的解。

思路:

利用尺取法查找最小[x,y]并且满足k个区间。最后遍历数组。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        int n,k;cin>>n>>k;
        vector<int>cnt(n+1,0),arr(n+1,0);
        for(int i=1;i<=n;i++){
            cin>>arr[i];
            cnt[arr[i]]++;
        }
        int x=0,y=INT_MAX;
        int sum=0;//[x,y]范围内元素的个数
        for(int l=1,r=1;l<=n;l++){
            /*
                n-sum表示不在[x,y]范围内的元素个数
                sum-(n-sum)表示[x,y]范围内的元素个数和不在[x,y]范围的个数差大于k(说明可以组合k个区间)
                sum-(n-sum)=2*sum-n
            */
            while(r<=n&&2*sum-n<k){
                sum+=cnt[r++];
            }
            if(2*sum-n>=k){
                if(r-l<y-x+1){
                    x=l;
                    y=r-1;
                }
            }
            sum-=cnt[l];
        }
        cout<<x<<" "<<y<<endl;
        sum=0;//此时sum表示[l,r]的[x,y]范围内的元素个数
        int last=0;
        //需要留一个收尾(题目要是arr中的每个元素都要在子数组中)
        for(int i=1;i<=n&&k>1;i++){
            sum+=((arr[i]>=x&&arr[i]<=y)?1:-1);
            if(sum>0){
                cout<<last+1<<" "<<i<<endl;
                last=i;
                sum=0;
                k--;
            }
        }
        cout<<last+1<<" "<<n<<endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Puzzle harvester

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值