概述

啥都不会,滚出。

期望 $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;
}