• [2020多校联考]手套


    [BalticOI 2008]手套

    Description

    有两个可重集 (A)(B),每个集合里有若干元素,每种元素有若干个。可以选择从 (A) 集中等概率随机选 (x) 个到 (C 集),从 (B) 中等概率随机选择 (y) 个到 (D),使得一定会使 (C)(D) 有交。最小化 (x+y),在 (x+y) 相等时最小化 (x)

    Solution

    因为要使得一定有交,所以考虑选了一定数目后,没有交的最坏情况。最坏情况显然是对于每种元素,其中一个集合中的该元素取完了,而另一个集合中的该元素一个都没有取到。而每种选择情况都会构成一个点 ((x,y)),那么显然对所有 (x'<x)(y' <y) 的选择方案 ((x',y')) 一定都不能构成合法方案,因为 ((x,y)) 最坏。

    考虑 ((x+1,y+1)),因为 ((x,y)) 最坏,再加入一个元素后,一定可以构成一组合法方案。所以只需要统计边界上的点,从而更新出合法的点的坐标即可。

    显然棕色点比红色点优((x+y) 小),所以用两个边界上的点更新一个合法的点。对于一组非法点 ((x_{i-1},y_{i-1}))((x_i,y_i)) ,可以构造出一个合法点 ((x_{i-1}+1,y_i+1))

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    #define N 21
    
    struct Node{
        int x,y;
        bool operator <(const Node &X) const{
            return x==X.x? y>X.y:x<X.x;
        }
    }a[N],s[1<<N],sta[1<<N];
    
    int top,n;
    int main(){
        freopen("gloves.in","r",stdin);
        freopen("gloves.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i].x);
        for(int i=1;i<=n;i++) scanf("%d",&a[i].y);
        int p=1<<n;
        for(int i=1;i<=p;i++)
            for(int j=0;j<n;j++)
                if((i>>j)&1) s[i].x+=a[j+1].x;
                else s[i].y+=a[j+1].y;
        sort(s+1,s+1+p);
        s[0].x=s[1].x+114514;
        for(int i=1;i<=p;i++){
            if(s[i].x==s[i-1].x) continue;
            while(top&&sta[top].y<=s[i].y) top--;
            sta[++top]=s[i];
        }
        int ans=(1<<30)+(1<<29)+(1<<28)+((114514-114513)<<27),x,y;
        for(int i=2;i<=top;i++){
            int ret=sta[i].y+sta[i-1].x+2;
            if(ret<ans) ans=ret,x=sta[i-1].x+1,y=sta[i].y+1;
        }
        printf("%d
    %d",x,y);
    }
    /*
    4
    0 7 1 6
    1 5 0 6
    */
    
  • 相关阅读:
    获取请求浏览器信息
    (转)获取页面 鼠标位置
    (转)location.href 用法
    (转)异常的处理
    (转载)提高ASP.NET Web应用性能的技巧
    赶集网二手数据.py
    豆瓣top250.py
    爬取58二手数据.py
    使用类和实例.py
    爬取小猪短租房.py文件
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14063981.html
Copyright © 2020-2023  润新知