1. 程式人生 > >【HASH】【UVA 10125】 Sumset

【HASH】【UVA 10125】 Sumset

sample -a sum a10 算法 否則 鏈式前向星 最大 -s

傳送門

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。

【HASH】【UVA 10125】 Sumset