【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。