hihocoder#1707 : The troublesome Kth problem (two points)

Time limit: 10000ms
Single point time limit: 1000ms
Memory Limit: 256MB

describe

Given n numbers, let the notation [l, r, t] denote the t-th largest value among the l-th to r-th numbers.

For given len, y and k, find the kth largest value in the multiset {[l,r,(r-l+1)/len*y] | (r-l+1) mod len=0}

Specifically, this multiset contains:

Each length is the y-th largest value in the interval of len,

Each length is the 2yth largest value in the interval of 2len,

Each length is the 3yth largest value in the interval of 3len,

……

And so on.

For the example below, the multiset is {2, 3, 3, 4}

enter

Four numbers in the first line, n, len, y, k (n ≤ 100000, y ≤ len ≤ n, k ≤ the number of intervals whose length is a multiple of len)

n in the second row, each number ≤ n

output

output a number to indicate the answer

sample input
4 2 1 3
2 1 3 4
Sample output
3
Ideas:

The binary answer ans 
regards the original array greater than or equal to ans as len-y, and the less than ans as -y, 
and then counts how many (length is a multiple of len) the sum of the interval is greater than or equal to 0, denoted as C

According to the size relationship between C and K, decide whether to divide the answer to the left or to the right.

You can use the prefix offset and tree array to count how many (length is a multiple of len) the sum of the interval is greater than or equal to 0.

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+30;
const int MOD=1e9+9;
const double PI=acos(-1.0);
typedef long long ll;
int a[MAX],n,len,y;
ll A[MAX],b[MAX],c[MAX],v[MAX];
void add(int x,int y)
{
    while(x<=n+1)
    {
        A[x]+=y;
        x+=x&(-x);
    }
}
ll ask(int x)
{
    ll ans=0;
    while(x)
    {
        ans+=A[x];
        x-=x&(-x);

    }
    return ans;
}
ll check(int x)
{
    for(int i=1;i<=n;i++)
    {
        b[i]=a[i]>=x?len-y:-y;
        b[i]+=b[i-1];
        c[i]=b[i];
    }
    c[n+1]=0;
    sort(c+1,c+n+2);
    int cd=unique(c+1,c+n+2)-c-1;
    for(int i=0;i<=n;i++)v[i]=lower_bound(c+1,c+cd+1,b[i])-c;//Discretize the value of the prefix sum for convenience insert tree array
    ll ans=0;
    for(int i=0;i<len;i++)//The prefix offset enumerates all intervals
    {
        add(v[i],1);
        for(int j=i+len;j<=n;j+=len)
        {
            ans+=ask(v[j]);//Count how many b[x]<=b[j] in the prefix and b[x] inserted before, that is, how many with j at the end of length len The interval sum is greater than or equal to 0.
            add(v[j],1);
        }
        add(v[i],-1);//Clear the tree array
        for(int j=i+len;j<=n;j+=len)add(v[j],-1);
    }
    return ans;
}
intmain()
{
    ll k;
    cin>>n>>len>>y>>k;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    int l=-1e9,r=n,ans=0;
    while(r>=l)
    {
        int mid=(l+r)/2;
        if(check(mid)>=k)
        {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325164967&siteId=291194637