C. 2026

注意到 \(0 < x < y < \sqrt{n}\),所以直接枚举 \((x, y)\) 即可

代码实现
#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<int> cnt(n+1);
    for (int x = 1; x*x < n; ++x) {
        for (int y = x+1; x*x+y*y <= n; ++y) {
            cnt[x*x+y*y]++;
        }
    }
    
    vector<int> ans;
    for (int i = 1; i <= n; ++i) {
        if (cnt[i] == 1) ans.push_back(i); 
    }
    
    cout << ans.size() << '\n';
    for (int x : ans) cout << x << ' ';
    
    return 0;
}

D. Kadomatsu Subsequence

统计合法的 \((j, ?, ?)\)\((?, ?, j)\) 的个数
对于 \(i\)\(k\) 的顺序无所谓
\(7:5:3\) 可以看成是 \(7x:5x:3x\)
通过枚举 \(j\),我们可以得知 \(x=\frac{a_j}{5}\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    ll ans = 0;
    rep(ri, 2) {
        map<int, int> cnt;
        for (int na : a) {
            cnt[na]++;
            if (na%5 == 0) {
                int x = na/5;
                ans += (ll)cnt[x*3]*cnt[x*7];
            }
        }
        reverse(a.begin(), a.end());
    }
    
    cout << ans << '\n';
    
    return 0;
}

E. Kite

其实就是求 \((A_i, B_i)\) 的最长上升子序列
注意到,当 \(A_i = A_j\) 时,也算冲突
如果将 \(A_i\) 作为第一关键字做升序,将 \(B_i\) 作为第二关键字也做升序排序的话,就会产生上面的冲突。解决办法是将 \(B_i\) 作为第二关键字做降序排序

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using P = pair<int, int>;

int main() {
    int n;
    cin >> n;
    
    vector<P> ab;
    rep(i, n) {
        int a, b;
        cin >> a >> b;
        ab.emplace_back(-a, b);
    }
    
    sort(ab.begin(), ab.end(), greater<>());
    vector<int> b;
    rep(i, n) b.push_back(ab[i].second);
    
    const int INF = 1001001001;
    vector<int> dp(n+1, INF);
    dp[0] = -1;
    int ans = 0;
    for (int nb : b) {
        int i = lower_bound(dp.begin(), dp.end(), nb) - dp.begin();
        dp[i] = nb;
        ans = max(ans, i);
    }
    
    cout << ans << '\n';
    
    return 0;
}

F. Beautiful Kadomatsu

不难发现,峰和谷是交替出现的,那么为了保证峰比谷多,只需让首尾都是峰就行,也就是开头两个数升序,末尾两个数降序。对于中间的数随意。
那么答案就是 \(\sum\limits_{l < r} a_lb_r2^{r-l-1} + \sum a_ib_i\),其中 \(a_i\) 表示 \(i\) 左边 \(< p_i\) 的数的个数,\(b_i\) 表示 \(i\) 右边 \(< p_i\) 的数的个数

代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using mint = modint998244353;

int main() {
    int n;
    cin >> n;
    
    vector<int> p(n);
    rep(i, n) cin >> p[i], p[i]--;
    
    vector<mint> a(n), b(n);
    {
        fenwick_tree<int> t(n);
        rep(i, n) {
            a[i] = t.sum(0, p[i]);
            t.add(p[i], 1);
        }
    }
    {
        fenwick_tree<int> t(n);
        for (int i = n-1; i >= 0; --i) {
            b[i] = t.sum(0, p[i]);
            t.add(p[i], 1);
        }
    }
    
    vector<mint> two(n+1, 1), owt(n+1);
    rep(i, n) two[i+1] = two[i]*2;
    owt[n] = two[n].inv();
    for (int i = n; i >= 1; --i) owt[i-1] = owt[i]*2;
    
    mint ans, lsum;
    rep(i, n) {
        ans += lsum*b[i]*two[i];
        ans += a[i]*b[i];
        lsum += a[i]*owt[i+1];
    }
    
    cout << ans.val() << '\n';
    
    return 0;
}