hiho一下 第241周 1483 区间价值

题面 :

Link

题意:

n个数,他们相同的数的次数就是区间的价值,求n个数价值第k大区间的价值是?

思路:

最暴力求出n*(n+1)/2区间不同的值,然后排序求第k大的值,明显TLE。
我们先分析发现区间越大,价值肯定越大,并且呈单调性。我们就可以用二分去查找第k大的值。
对于每次二分的check,这里利用尺取的思想,尺取从左往右扫一遍最大区间[L,R]里的价值都是小于二分的mid,累加后可以在O(n)时间内统计出n个数里比mid价值小的区间个数,总的时间复杂度就变成O(nlogn)。在统计每个数出现次数时可以用map会超时,而n的范围可以用数组存下,但数值范围太大,于是用离散化操作。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
typedef long long ll;
ll a[N],temp[N],n,k;
int vis[N];
ll check(ll mid)//尺取求比mid小的区间个数
{
    ll sum = 0,num = 0;
    memset(vis,0,sizeof(vis));
    for(int i=0,j=0;i<n;i++)
    {
        for(;j<n&&sum+vis[a[j]]<=mid;j++)
        {
            sum += vis[a[j]];
            vis[a[j]]++;
        }
        num += j-i;//当前i,j范围内i作为起点的j个不同区间内值都比mid小
        vis[a[i]]--;
        sum -= vis[a[i]];
    }
    return num>=k;
}


int main(){
    int T;cin>>T;
    while(T--){
        cin>>n>>k;
        for(int i=0;i<n;i++){
            cin>>a[i];
            temp[i] = a[i];
        }
        int cnt;
        sort(temp,temp+n);
        cnt = unique(temp,temp+n) - temp;
        for(int i=0;i<n;i++){
            a[i] = lower_bound(temp,temp+cnt,a[i]) - temp; //离散化操作
        }
        ll l= 0,r = n*(n-1)/2;
        while(l<=r){
            ll mid = (l+r)/2;
            if(check(mid)) r = mid-1;//说明mid大了
            else l = mid+1;
        }
        cout<<r+1<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值