• 【HASH】【UVA 10125】 Sumset


    传送门

    Description

      给定一个整数集合S,求一个最大的d,满足a+b+c=d,其中a,b,c,d∈S

    Input

      多组数据,每组数据包括:

    • 第一行一个整数n,代表元素个数
    • 下面n行每行一个整数,代表集合元素

      输入结束的标志为n=0。

    Output

      对于每组数据,输出:

    • 一行,如果有解,输出一个整数,代表最大的d;否则输出no solution

    Sample Input

    5
    2
    3
    5
    7
    12
    5
    2
    16
    64
    256
    1024
    0

    Sample Output

    12
    no solution

    Hint

    n≤1000,保证输入的集合元素互不相同。

    集合中的元素∈[-536 870 912,536 870 911]。

    Solution

    考虑暴力做法:暴力枚举a,b,c,d,复杂度O(n4),无法承受。

    考虑对于给定的d,和c,有唯一确定的a+b的值与之对应。所以我们考虑使用O(n2)的时间枚举可以产生的a+b的值并进行存储,然后枚举d和c,计算出d-c=a+b,判断是否可行。

    如何存储a+b呢?普通数组显然开不下,考虑使用set或者map,我们发现在极端情况下,整个算法的复杂度为O(n2logn)。大概是108大小的运算量。考虑到多组数据,这个这个复杂度要GG。

    考虑使用HASH,将a+b的值作为hash值,在信息中存储a+b的值,a的下标和b的下标,将hash值相同的按照链式前向星的形式挂成链。期望意义下的复杂度为O(n2),可以通过本题。

    另外,如果担心取模变慢,在代码中我采取了&19260817的方式代替取模,但是在链的长度上,应该不如膜大质数的方式。科学性有待考证

    Code

    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define rg register
    #define ci const int
    
    inline void qr(int &x) {
        char ch=getchar(),lst=NULL;
        while(ch>'9'||ch<'0') lst=ch,ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        if (lst=='-') x=-x;
    }
    
    char buf[20];
    inline void write(int x,const char aft,const bool pt) {
        if(x<0) {putchar('-');x=-x;}
        int top=0;
        do {
            buf[++top]=x%10+'0';
            x/=10;
        } while(x);
        while(top) putchar(buf[top--]);
        if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
    template <typename T>
    inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
    template <typename T>
    inline T mabs(const T &a) {if(a<0) return -a;return a;}
    
    template <typename T>
    inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}
    
    const int maxn = 1010;
    const int maxt = 1000010;
    const int upceil = 19260817;
    
    struct HASH {
        int v,nxt,a,b;
    };
    HASH lst[maxt];int hd[upceil+1],cnt;
    inline void ist(ci v,ci key,ci a,ci b) {
        HASH &now=lst[++cnt];
        now.v=v;now.nxt=hd[key];now.a=a;now.b=b;hd[key]=cnt;
    }
    
    inline int get_HASH(ci x) {
        return ((x<<1)+(x>>1))&upceil;
    }
    
    inline bool judge(ci a,ci b,ci c,ci d) {
        if(a==c||a==d||b==c||b==d) return false;
        return true;
    }
    
    int n,MU[maxn];
    
    void clear() ;
    
    int main() {
        qr(n);
        while(n) {
            clear();
            for(rg int i=1;i<=n;++i) qr(MU[i]);
            std::sort(MU+1,MU+1+n);
            for(rg int i=1;i<=n;++i) 
                for(rg int j=i+1;j<=n;++j) {
                    ist(MU[i]+MU[j],get_HASH(MU[i]+MU[j]),i,j);
                }
            for(rg int i=n;i;--i) {
                for(rg int j=1;j<=n;++j) if(i!=j) {
                    int delta=MU[i]-MU[j];
                    int k=get_HASH(delta);
                    if(!hd[k]) continue;
                    for(int h=hd[k];h;h=lst[h].nxt) if(lst[h].v==delta) {
                        if(judge(lst[h].a,lst[h].b,i,j)) {write(MU[i],'
    ',true);goto loop;}
                    }
                }
            }
            puts("no solution");
            loop:
            n=0;qr(n);
        }
    }
    
    void clear() {
        memset(hd,0,sizeof hd);
        memset(MU,0,sizeof MU);
        memset(lst,0,sizeof lst);
        cnt=0;
    }

    Summary

    考虑存储一个元素的多个信息且map复杂度超标的时候,不妨考虑HASH。

  • 相关阅读:
    高并发计算服务器数量
    Java子线程中操作主线程Private级别数据
    Java线程并发中常见的锁--自旋锁 偏向锁
    Java锁之自旋锁详解
    Java多线程:向线程传递参数的三种方法
    TPS、并发用户数、吞吐量关系
    C/C++中near和far的区别
    qt的pos()和globalpos()(globalpos是相对于桌面的)
    如何获得 Qt窗口部件在主窗口中的位置--确定鼠标是否在某一控件上与在控件上的位置
    QComboBox实现复选功能(三种方法:嵌套QListWidget, 设置QStandardItemModel, 设置Delegate)
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9440390.html
Copyright © 2020-2023  润新知