概述
啥都不会,滚出。
期望 $0+100+0+20=120$,实际 $0+20+0+20=40$。至于为什么挂了这么多,看下文。
赛时
T1 概率+博弈论,再见吧。。。
T2 看着也不简单。
T3 计算几何?????
T4 又是个什么鬼玩意??????
稍微思考了一下除了 T2 以外的题,似乎都不可做。
那没啥说的,做 4h T2吧。
于是开始做。
分类呗,6个木条正方形,1122 或者 1113。
1122 很快就搞出来了,双指针随便算一下就行。
这个 1113 就很离谱。。。。
随便搞了搞之后发现会算重复。。。。
想了很久,忽然意识到去重不是容斥原理干的事吗。。。
于是开始往死里容斥。
想了很久可算是搞出来了,过了几组手造小数据。也不想对拍了,随便吧。。。
又发现 T4 有 $20$ 分是个斐波那契,给写了。
T3 其实也能写点暴力,但我不想思考也不想打代码了,就这样吧。。。
感觉四道全是数学题。。。
赛后
我吐了,我 T2 忘记自己拷贝的一个数组没有排序了。。。导致 $90$ 挂成了 $20$,再在两个地方开 long long
就 $100$ 了。。。
结果我挂成了和最暴力的暴力一个分,我吐了。。。
总结
没啥好总结的,也许 T3 暴力还是应该想想怎么做。。。。
emmmm,其实 T1 不是那么难——遇到最大最小值可以考虑转化成函数然后三分。但我确实不会。。。
T3、4 都是我不懂的知识,告辞。
还是应该对拍,手造数据不靠谱(我手造的数据都是排好序的。。。)
附专治低血压代码:
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <map>
using std::cout;
using std::endl;
const int maxn = 5010, maxi = 1e7 + 10;
typedef long long ll;
int a[maxn], b[maxi], n, m, t[maxn];
ll C(ll n, ll m)
{
if (m > n)
return 0;
ll res = 1;
for (int i = n; i >= n - m + 1; i--)
res *= i;
for (int i = m; i >= 2; i--)
res /= i;
//cout << n << " " << m << " " << res << endl;
return res;
}
bool ok[maxi * 2];
ll work1()
{
ll res = 0;
for (int i = 1; i <= m; i++)
{
if (b[a[i]] >= 2)
{
ll cnt = 0, tot = 0; // cnt 对数;tot 总数
for (int l = 1, r = i - 1; l <= r; r--)
{
while (l <= r && a[r] + a[l] < a[i])
l++;
if (l > r || a[l] + a[r] != a[i])
continue;
if (l == r)
{
tot += C(b[a[l]], 4);
tot += C(b[a[l]], 2) * cnt;
break;
}
if (b[a[l]] >= 2 && b[a[r]] >= 2)
tot += C(b[a[l]], 2) * C(b[a[r]], 2);
tot += b[a[l]] * b[a[r]] * cnt;
cnt += b[a[l]] * b[a[r]];
}
//if (tot != 0)
//cout << i << " " << a[i] << " " << cnt << " " << tot << endl;
res += C(b[a[i]], 2) * tot;
}
}
return res;
}
int mp[maxi + 50];
/*
1 2 3 得到 6 -> 重复计算 3 次
total = 全部 - 有两个相同 + 三个相同(1)
*/
ll work2()
{
//for (int i = 1; i < m; i++)
// for (int j = i + 1; j <= m; j++)
// if (a[i] + a[j] < maxi)
// cout << a[i] << " " << a[j] << " " << b[a[i]] << " " << b[a[j]] << endl, mp[a[i] + a[j]] += b[a[i]] * b[a[j]], ok[a[i] + a[j]] = 1;
//for (int i = 1; i <= 6; i++)
// cout << mp[i] << endl;
ll res = 0;
for (int i = 1; i <= m; i++)
{
if (b[a[i]] >= 3)
{
int tot = 0; // 1
for (int j = 1; j <= n; j++)
{
if (t[j] > a[i])
break; // 把此处 break 改为 continue 可获得 90 分
int d = 0; // 2
if (t[j] * 2 <= a[i])
{
d = b[a[i] - t[j] * 2];
if (t[j] * 3 == a[i])
d--;
}
tot += mp[a[i] - t[j]] - d;
}
// 再把上方 1 2 都改为 long long 可获得 100 分
res += tot / 3 * C(b[a[i]], 3);
}
}
return res;
}
int main()
{
freopen("stick.in", "r", stdin);
freopen("stick.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), b[a[i]]++, t[i] = a[i]; // 写这个代码的人,数组 t 你没排序啊!!!
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
if (a[i] + a[j] < maxi)
mp[a[i] + a[j]]++;
std::sort(a + 1, a + 1 + n);
m = std::unique(a + 1, a + 1 + n) - a - 1;
//for (int i = 1; i <= m; i++)
// cout << a[i] << " " << b[a[i]] << endl;
//cout << endl;
printf("%lld\n", work1() + work2());
return 0;
}