#哈希#ZJU 1101 赌徒

本文探讨了一种针对特定数列求和问题的算法优化方案,通过哈希表和快速排序结合二分查找的方法,将原始O(n^4)的时间复杂度降低到O(n^2)或O(n^2log_2n)。文章提供了两种实现方式的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

把一个数列的三个数加起来等于数列中的另一个数,使和最大。


分析

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)O2n2log2n

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值