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);
}

浙公网安备 33010602011771号