题目
把一个数列的三个数加起来等于数列中的另一个数,使和最大。
分析
a[x1]+a[x2]+a[x3]=a[x]a[{x1}]+a[{x2}]+a[{x3}]=a[x]a[x1]+a[x2]+a[x3]=a[x]
转换成
a[x1]+a[x2]=a[x]−a[x3]a[{x1}]+a[{x2}]=a[x]-a[{x3}]a[x1]+a[x2]=a[x]−a[x3]
首先这道题普通模拟O(n4n^4n4)必然超时,so我们用二重循环算出任意两数之和,再来一个二重循环,哈希。O(2n22n^22n2)
哈希
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define p 1200007
#define q (pos+k)%p
using namespace std;
struct tree{
int x,y,s;
}hash[p+1];
int n,a[1001];
int in(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)&&c!='-') c=getchar();
if (c=='-') c=getchar(),f=-f;
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int abs(int x){return (x>0)?x:-x;}
int locate(int x){
int pos=abs(x)%p,i=0;
if (i<p&&hash[(pos+i)%p].s&&hash[(pos+i)%p].s!=x) i++;
return (pos+i)%p;
}
int main(){
while (n=in(),n){ int x,ans; bool flag=0;
memset(hash,0,sizeof(hash));
for (int i=1;i<=n;i++) a[i]=in();
stable_sort(a+1,a+1+n);
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++){
int pos=locate(a[i]+a[j]);
hash[pos].s=a[i]+a[j];
hash[pos].x=i; hash[pos].y=j;
}
for (int i=n;i>=1;i--){
for (int j=1;j<=n;j++){
int pos=locate(a[i]-a[j]),k=0;
if (hash[pos].s!=(a[i]-a[j])||i==j) continue; //重复或找不到
while (k<p&&hash[q].s==(a[i]-a[j])&&(hash[q].x==i||hash[q].y==i||hash[q].x==j||hash[q].y==j)) k++;//往后找符合的
if (k==p||hash[q].s!=(a[i]-a[j])) continue;//没有
else flag=1,ans=a[i];//找到
if (flag) break;
}
if (flag) break;
}
if (flag) printf("%d\n",ans); else puts("no solution");
}
return 0;
}
快排+二分代码O(2n2log2n)O(2n^2log_2n)O(2n2log2n)
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int n,a[1001];
struct rec{
int x,y,s;
}t[1000001];
int in(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)&&c!='-') c=getchar();
if (c=='-') c=getchar(),f=-f;
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int erfen(int l,int r,int x){//二分查找
int mid;
while (l<=r){
mid=(l+r)>>1;
if (t[mid].s>x) r=mid-1;
else if (t[mid].s<x) l=mid+1;
else return mid;
}
return 2147483647;
}
bool cmp(rec r,rec c){return r.s<c.s;}
int main(){
while (n=in(),n){ int m=0,ans; bool flag=0;
for (int i=1;i<=n;i++) a[i]=in();
stable_sort(a+1,a+1+n);
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++){
t[++m].s=a[i]+a[j]; t[m].x=i; t[m].y=j;
}
stable_sort(t+1,t+1+m,cmp);
for (int i=n;i>=1;i--){
for (int j=1;j<=n;j++){
int si,l,r;
if (i==j||(si=l=r=erfen(1,m,a[i]-a[j]))==2147483647) continue;
if (t[si].x!=i&&t[si].y!=i&&t[si].x!=j&&t[si].y!=j) flag=1,ans=a[i];
else{
while (l>0&&t[l].s==(a[i]-a[j])&&(t[l].x==i||t[l].y==i||t[l].x==j||t[l].y==j)) l--;
if (t[l].s==(a[i]-a[j])&&l) flag=1,ans=a[i];//左边
if (flag) break;
while (r<=m&&t[r].s==(a[i]-a[j])&&(t[r].x==i||t[r].y==i||t[r].x==j||t[r].y==j)) r++;//右边
if (t[r].s==(a[i]-a[j])&&r<=m) flag=1,ans=a[i];
if (flag) break;
}
if (flag) break;
} if (flag) break;
}
if (flag) printf("%d\n",ans);
else puts("no solution");
}
return 0;
}