zoukankan      html  css  js  c++  java
  • Task

    Task

    给出大小为n的集合(S_1),其中第i个元素为((a_i,b_i)),给出大小为m的集合(S_2),第i个元素为((a_i,b_i)),现在要从集合(S_2)中选出元素i与集合(S_1)的元素j配对,但是要满足(a_ileq a_j),(b_ileq b_j),然后得到权值(a_i imes 500+b_i imes 2),询问满足配对数量尽可能多的情况下,最大的权值之和,(1 <= N <= 100000,1 <= M <= 100000),(a_ileq 1440,b_ileq 100)

    注意到这个问题考虑起来过于麻烦,于是需要转换模型,考虑转换为数列模型,不妨将两个集合合并成一个集合,并标记好属于哪个集合,属于(S_1)标记为1,否则标记为0,然后统一按照(b_i)为关键字从小到大排序,如果(b_i)相同则按起被标记的号子大小排序(含义就是属于(S_1)要在后面,往后看,你就知道为什么了),记新的数列中第i个元素为((a_i,b_i,l_i))(其中(l_i)对应其被标记的数字)。

    先考虑如何选得多。

    注意到此时对于其中一个(l_i=1)的元素,因为b已经从小到大排序,能够与之配对的元素j必然是它的前面的(l_j=0),且(a_jleq a_i)的元素,不妨暴力找出这些元素,现在问题是如何选择这些元素与i配对,朴素的感觉告诉我们最大的满足条件的(a_j)

    首先证明(i)能够选择一个元素与之配对,否则让出前面的元素给后面的不会配对的元素的配对,结果不改变,如果是让后面的一个会配对的元素配对,放弃它的配对的元素,从而可以让一个新的元素能够配对,也不会改变结果,于是i一定可以选择。

    然后对于i的选择,对于可以选择(j,k(a_k<a_j)),必然对于后面的元素,要么都不能选择,显然此时i选择一个元素是优秀的,要么是k能够选择,j不能选择,i选择了是优秀的,或者是都能选择,此时i选择任意一个都可以,于是选择(j)一定优秀。

    现在问题是如何查询小于(a_i)的最大的(a_j),决策集合有增减,显然想到维护单调性,于是一棵平衡树就可以支持查询这个元素(显然用set替代),并且支持快速插入和删除,于是我们可以做到选的多。

    现在问题在于如何使结果尽可能大,注意到一个性质,(a)带来的价值远大于(b),也就是一个b能够带来最大的权值为(200),而a增加一个数字,就能增加(500),于是只要让a尽可能优秀,结果就会更加优秀了,因此我们寻找尽可能大的(a_j)的策略保证了a最大,是非常优秀的。

    还存在一个问题,也就是如果(a_i)相同如何选择,显然选择(b_i)较大的,这个也不难,只要在平衡树再加一个关键字就是按照(b)排序,注意此时查询时,对应的b要赋值为无穷大(不理解看代码)。

    因此我们就可以(O(nlog(n)))解决这个问题,事实上你可以不用平衡树,因为(a_i)很小,可以桶排查找这个最大值,于是你可以改成在(O(na_i))解决这个问题,理论时间复杂度很高,但常数很小。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <set>
    #include <cstring>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    #define Size 250000
    #define intmax 0x7fffffff
    using namespace std;
    struct san{
        int x,y,l;
        il bool operator<(const san&a)const{
            return x==a.x?y<a.y:x<a.x;
        }
    }I[Size];
    multiset<san>S;
    multiset<san>::iterator gzy;
    il void read(int&);
    il bool comp(const san&,const san&);
    int main(){int n,m;
        while(scanf("%d%d",&n,&m)!=EOF){S.clear(),memset(I,0,sizeof(I));
            for(int i(1);i<=n;++i)read(I[i].x),read(I[i].y),I[i].l=1;
            m+=n;for(int i(n+1);i<=m;++i)read(I[i].x),read(I[i].y);
            sort(I+1,I+m+1,comp);int tot(0);ll ans(0);
            for(int i(1);i<=m;++i){
                if(I[i].l){
                    if(S.empty())continue;
                    I[i].y=intmax,gzy=S.upper_bound(I[i]);
                    if(gzy==S.begin())continue;
                    --gzy,++tot,ans+=gzy->x*500+gzy->y*2;
                    S.erase(gzy);
                }else S.insert(I[i]);
            }printf("%d %lld
    ",tot,ans);
        }
        return 0;
    }
    il bool comp(const san&a,const san&b){
        return a.y==b.y?a.l<b.l:a.y<b.y;
    }
    il void read(int &x){
        x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
  • 相关阅读:
    linux安装java环境
    win7+ubuntu双系统安装攻略
    Ubuntu 安装基础教程
    我学到的算法
    linux使用su切换用户提示 Authentication failure的解决方法& 复制文件时,报cp: omitting directory `XXX'
    我新买的红米手机,新浪和360浏览器都能进,也能看电视,就是不能上手机QQ和微信
    电脑如何设置自动开机
    jsp分页技术
    发光文本框样式
    子元素div高度不确定时父div高度如何自适应
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11234277.html
Copyright © 2011-2022 走看看