把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

qzezoj 1589 好元素

题面传送门
考虑用哈希折半搜索来解决。
观察以下原式\(a_m+a_n+a_p=a_i,m,n,p<i\)考虑移项得到\(a_m+a_n=a_i-a_p,m,n,p<i\),那么两边就可以分别枚举了。
代码实现:

#include<cstdio>
#include<cstring>
#include<cmath>
#define abs(x) ((x)>0?(x):-(x))
#define mod 16000017
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,a[5039],ans,pus,f[12500039],z[12500039],h[16000039],head,maxn,minn;
inline void add(register int x) {
	register int now=abs(x)%mod,ss=h[now];
	while(ss) {if(f[ss]==x) break;ss=z[ss];}
	if(!ss) f[++head]=x,z[head]=h[now],h[now]=head;
}
inline int _hash(register int x) {
	register int now=abs(x)%mod,ss=h[now];
	while(ss) {if(f[ss]==x) break;ss=z[ss];}
	if(!ss)return 0;
	else return 1;
}
inline void read(register int &x) {
	char s=getchar();int f=1;x=0;
	while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();};
	while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
	x*=f;
}
int main() {
//	freopen("1.in","r",stdin);
	//memset(h,-1,sizeof(h));
	register int i,j;
	scanf("%d",&n);
	for(i=1; i<=n; i++) read(a[i]),maxn=max(maxn,a[i]),minn=min(a[i],minn);
	for(i=1; i<=n; ++i) {
		for(j=1; j<i; ++j)if(_hash(a[i]-a[j])) {ans++;break;}
		for(j=1; j<=i; ++j)add(a[i]+a[j]);
	}
	printf("%d\n",ans);
}
posted @ 2020-04-06 17:16  275307894a  阅读(35)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end