枚举 (Theta(n)) 种正方形的边长 (L) , 不难发现在选的 (6) 条边中只可能有 (2) 条 / (3) 条 边的长度为 (L) .
有 (2) 条边长为 (L) :
另外两条边分别由两个比 (L) 小的数拼接而成。枚举拼成 L 的方式 ( 即 (L = x + y) ,((x leq y)) 的 (x) 和 (y) ) , 不难发现每种方式之间相互独立,然后分别考虑一下只用这种方式 / 使用两种不同方式 的方案数并求和即可。
有 (3) 条边长为 (L) :
剩下的一条边由三个加起来 (=L) 的数字拼接而成,不妨设 (L = x + y + z(xleq yleq z)) , 先 (Theta(n)) 处理 (x = y = z) 或者 (x = y < z) 或者 (x < y = z) 的三种情况。
最后 (x < y < z) , 枚举 z 之后变成查询前 (i) 种数拼成 (L-z) 的方案数 , 这个可以离线下来做。
(Theta(n^2))
code :
#include <bits/stdc++.h>
#define LL long long
using namespace std;
template <typename T> void read(T &x){
static char ch; x = 0,ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
const int N = 5005,M = 10000005<<1;
int id[M],cnt[M],n,a[N],m,b[N]; LL c[N],c2[N],c3[N],c4[N],ans;
inline LL calc1(int x){
LL ans = 0,s = 0; register int now,i,j;
for (i = 1; i <= m && b[i] <= x>>1; ++i) if (j = id[x-b[i]]){
if (i == j) now = c2[i],ans += c4[i];
else now = c[i] * c[j],ans += c2[i] * c2[j];
ans += s * now,s += now;
}
return ans;
}
inline LL calc2(int x){
LL ans = 0; register int i,j;
if (x % 3 == 0) ans += c3[id[x/3]];
for (i = 1; i <= m && b[i] < x; ++i)
if ((b[i]<<1) <= x && (j = id[x-(b[i]<<1)]) && b[j] != b[i]) ans += c[j] * c2[i];
return ans;
}
int main(){
register int i,j;
read(n);
for (i = 1; i <= n; ++i) read(a[i]); sort(a+1,a+n+1);
for (i = 1; i <= n; ++i) if (i == 1 || a[i] != a[i-1]) b[++m] = a[i];
for (i = 1; i <= m; ++i) id[b[i]] = i;
for (i = 1; i <= n; ++i) ++c[id[a[i]]];
for (i = 1; i <= m; ++i) c2[i] = c[i] * (c[i]-1) / 2,c3[i] = (LL)c[i] * (c[i]-1) * (c[i]-2) / 6,c4[i] = (LL)c[i] * (c[i]-1) * (c[i]-2) * (c[i]-3) / 24;
for (i = 1; i <= m; ++i) if (c[i] >= 2) ans += c2[i] * calc1(b[i]);
for (i = 1; i <= m; ++i) if (c[i] >= 3) ans += c3[i] * calc2(b[i]);
for (i = 1; i < m-1; ++i){
for (j = 1; j < i; ++j) cnt[b[j] + b[i]] += c[i] * c[j];
for (j = i+2; j <= m; ++j) ans += c3[j] * cnt[b[j]-b[i+1]] * c[i+1];
}
cout << ans << '
';
return 0;
}