zoukankan      html  css  js  c++  java
  • 51NOD 1821 最优集合 [并查集]

    传送门

    题意:

    一个集合S的优美值定义为:最大的x,满足对于任意i∈[1,x],都存在一个S的子集S',使得S'中元素之和为i。

    给定n个集合,对于每一次询问,指定一个集合S1和一个集合S2,以及一个数k,要求选择一个S2的子集S3(|S3|<=k),使得S1∪S3的优美值最大。(集合元素可以重复)
    $n,m le 1000, Q le 1000$

    比赛时看了一眼题没认真想其实不难....现在想出来(也晚了)
    考虑如何求最优值
    如果现在最优值为$now$,只要找到下一个未用的$le now+1$的最小元素$x$,最优值就可以变成$now+x$
    如果找不到怎么办?去$S2$里找$le now+1$的未用的最大元素
    实现上可以用一个并查集记录某一个元素的上一个(包括自己)未用元素是谁做到$alpha(m)$
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=1005;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,a,b,k;
    struct Set{
        int s[N],m;
        int& operator [](int x){return s[x];}
        void Sort(){sort(s+1,s+1+m);}
    }s[N];
    int fa[N];
    inline int find(int x){return x==fa[x] ? x : fa[x]=find(fa[x]);}
    void solve(Set &a,Set &b,int k){
        //printf("%d  ",a.m);for(int i=1;i<=a.m;i++) printf("%d ",a[i]);puts("");
        //printf("%d  ",b.m);for(int i=1;i<=b.m;i++) printf("%d ",b[i]);puts("");
        int n=a.m , m=b.m;
        for(int i=1;i<=m;i++) fa[i]=i;
        int now=0,p1=1,p2=1;
        while(true){//printf("now %d %d %d
    ",now,p1,p2);
            if(p1<=n && a[p1]<=now+1) now+=a[p1++];
            else if(k){ k--;
                while(p2<=m && b[p2]<=now+1) p2++;
                p2--;
                if(fa[p2]==p2) fa[p2]=find(p2-1),now+=b[p2++];
                else{
                    int x=find(p2);//printf("x %d
    ",x);
                    if(x) fa[x]=find(x-1),now+=b[x];
                    else break;
                }
            }else break;
        }
        printf("%d
    ",now);
    }
    int main(){
        freopen("in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++){
            s[i].m=read();
            for(int j=1;j<=s[i].m;j++) s[i][j]=read();
            s[i].Sort();
        }
        int Q=read();
        while(Q--){
            a=read();b=read();k=read();
            solve(s[a],s[b],k);
        }
    }
     
     
     
  • 相关阅读:
    wireshark筛选器汇总
    .net中的"异步"-手把手带你体验
    Javascript手记-垃圾收集
    Sqlserver作业-手把手带你体验
    oracle11g重置system密码,外二
    return Acad::ErrorStatus::eOk引发error C2220: warning treated as error
    RegOpenKeyEx和RegSetValueEx返回ERROR_SUCCESS,但注册表未发生变化。
    windows7 阻止copyfile到windows目录的解决办法
    如何让AutoCAD自动加载Arx,比如ArxDbg.arx
    入口点函数的19种消息,AcRxArxApp只处理16种。
  • 原文地址:https://www.cnblogs.com/candy99/p/6517790.html
Copyright © 2011-2022 走看看