【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],'\n',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。

posted @ 2018-08-07 23:53  一扶苏一  阅读(383)  评论(0编辑  收藏  举报