LOJ#6065. 「2017 山东一轮集训 Day3」第一题 题解
枚举 \(\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(x\leq y\leq 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 << '\n';
return 0;
}