Problem B: 专家系统 解题报告

Problem B: 专家系统

Description

一个专家系统是指,你雇佣了\(n\)个专家,他们每个人会做出一个结果,然后你从中选取较多的专家的结果组合而成最终的结果。专家系统广泛应用于传统机器学习领域、决策领域以及老师找学生做出一套试题的答案等等。

现在我们要在平面上找到一个点的坐标\((x, y)\),于是我们雇佣了\(n\)个专家,每个人都会给出一个坐标。为了得出一个较为准确的结果,我们选取其中的\(k\)名专家,他们得出的最小\(x\)坐标记为\(x_{\min}\),最小y坐标记为\(y_{\min}\),最大\(x\)坐标记为\(x_{\max}\),最大\(y\)坐标记为\(y_{\max}\),那么我们有理由相信,最终的这个点坐标一定落在\(x_{\min}\le x\le x_{\max}\), \(y_{\min}\le y\le y_{\max}\)之内。

但是选取不同的\(k\)名专家可能会导致不同的结果。为此,我们定义一个不确定度\(c=\max(x_{\max}-x_{\min},y_{\max}-y_{\min})\)

我们希望选出的\(k\)名专家使得\(c\)值尽可能的小,这样才能比较精确地获取这个点的坐标范围。现在,这个任务交给了你。

简述

现在有\(n\)个坐标\((x_i, y_i)\),你要从中选出\(k\)个。

假设你选出的全部\(k\)个坐标中,\(x\)坐标最小值为\(x_{\min}\)\(x\)坐标最大值为\(x_{\max}\)\(y\)坐标最小值为\(y_{\min}\)\(y\)坐标最大值为\(y_{\max}\)

那么你得出的不确定度\(c=\max(x_{\max}-x_{\min},y_{\max}-y_{\min})\)

你的目的是让\(c\)尽可能小。

由于可能有很多种选法能够达成这一目的,你只需要输出这个最小的\(c\)即可。

Input

第一行两个正整数\(n,k\), 空格分隔。

接下来\(n\)行,每行\(2\)个整数\(x_i, y_i\),空格分隔,表示一个坐标。

Output

仅一行,一个数,表示最小的\(c\)

HINT

对于\(20\%\)的数据, \(n\le 50\)
对于\(40\%\)的数据,\(n\le 300\)
对于\(60\%\)的数据,\(n\le 2000\)
对于\(80\%\)的数据,\(n\le 20000\)
对于\(100\%\)的数据,\(1\le n\le 100000\)
对于\(100\%\)的数据,\(1\le k\le n\)\(x_i\)\(y_i\)的绝对值不超过\(2000000000\)


首先吐槽,开2e9的范围..

考试的时候写了个看起来很套路的60分,二分答案然后拿两个指针按\(x\)扫描一下,然后朴素维护一下\(y\),结果因为不明原因爆0,现在都不晓得为啥。

事实上这个题非常的noip,考虑扫描\(x\)区间的时候如何维护\(y\)

每个\(y\)都被选上的时候可以钦定Ta为权值的右端点,设这个权值为\(d\),然后当前二分的值为\(c\),那么所有\(y\)值在\([d-c,d]\)的点都可以被选上。那么我们就可以考虑每个点对其他值域的贡献,其实就是\([d,d+c]\),贡献是个数\(1\)

然后我们可以离散化\(y\)坐标,把这些东西放在线段树里面,就是维护一个区间加和最大值就可以了。


Code:

#include <cstdio>
#include <algorithm>
const int N=1e5+10;
#define ll long long
const ll inf=(1ll<<40);
struct node
{
    ll x,y;
    bool friend operator <(node a,node b){return a.x<b.x;}
}dx[N];
int mx[N<<2],tag[N<<2];
using std::max;
#define ls id<<1
#define rs id<<1|1
void build(int id,int l,int r)
{
    mx[id]=tag[id]=0;
    int mid=l+r>>1;
    if(l^r) build(ls,l,mid),build(rs,mid+1,r);
}
void pushdown(int id)
{
    if(tag[id])
    {
        tag[ls]+=tag[id],tag[rs]+=tag[id];
        mx[ls]+=tag[id],mx[rs]+=tag[id];
        tag[id]=0;
    }
}
void change(int id,int L,int R,int l,int r,int d)
{
    if(l==L&&r==R)
    {
        tag[id]+=d,mx[id]+=d;
        return;
    }
    pushdown(id);
    int Mid=L+R>>1;
    if(r<=Mid) change(ls,L,Mid,l,r,d);
    else if(l>Mid) change(rs,Mid+1,R,l,r,d);
    else change(ls,L,Mid,l,Mid,d),change(rs,Mid+1,R,Mid+1,r,d);
    mx[id]=max(mx[ls],mx[rs]);
}
int n,m,k;ll dy[N];
bool check(ll d)
{
    build(1,1,m);
    int l=1,r=1,p;
    p=std::upper_bound(dy+1,dy+1+m,dy[dx[l].y]+d)-dy-1;
    change(1,1,m,dx[l].y,p,1);
    while(r<n&&dx[r+1].x-dx[l].x<=d)
    {
        ++r;
        p=std::upper_bound(dy+1,dy+1+m,dy[dx[r].y]+d)-dy-1;
        change(1,1,m,dx[r].y,p,1);
    }
    if(mx[1]>=k) return true;
    while(r<n)
    {
        ++r;
        while(dx[r].x-dx[l].x>d)
        {
            p=std::upper_bound(dy+1,dy+1+m,dy[dx[l].y]+d)-dy-1;
            change(1,1,m,dx[l++].y,p,-1);
        }
        p=std::upper_bound(dy+1,dy+1+m,dy[dx[r].y]+d)-dy-1;
        change(1,1,m,dx[r].y,p,1);
        if(mx[1]>=k) return true;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%lld%lld",&dx[i].x,&dx[i].y),dy[i]=dx[i].y;
    std::sort(dx+1,dx+1+n);
    std::sort(dy+1,dy+1+n);
    m=std::unique(dy+1,dy+1+n)-dy-1;
    for(int i=1;i<=n;i++) dx[i].y=std::lower_bound(dy+1,dy+1+m,dx[i].y)-dy;
    ll l=1,r=4000000000ll;
    while(l<r)
    {
        ll mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    printf("%lld\n",l);
    return 0;
}

2018.12.31

猜你喜欢

转载自www.cnblogs.com/ppprseter/p/10202388.html