T1:递推134数

本题难度中等,递推计数问题,需要使用高精度

假设数码和为 \(i\) 的个数有 \(dp[i]\)

递推式:

\[dp[i] = dp[i-1] + dp[i-3] + dp[i-4] \]

初始状态:

\(dp[1]=1\)\(dp[2] = 1\)\(dp[3] = 2\)\(dp[4] = 4\)

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

using namespace std;

// C = A + B
vector<int> add(vector<int> &A, vector<int> &B)
{
    vector<int> C;

    int t = 0;// 进位
    for (int i = 0; i < A.size() || i < B.size(); i++)
    {
        if (i < A.size())
            t += A[i];
        if (i < B.size())
            t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }

    if (t)
        C.push_back(1);
    return C;
}

int main() {
    int n;
    cin >> n;
    
    vector<vector<int>> dp(n+1, vector<int>(1000));
    dp[1][0] = 1, dp[2][0] = 1, dp[3][0] = 2, dp[4][0] = 4;
    for (int i = 5; i <= n; ++i) {
        auto now = add(dp[i-1], dp[i-3]);
        dp[i] = add(now, dp[i-4]);
    }
    
    int k = 999;
    while (!dp[n][k]) --k;
    for (int i = k; i >= 0; --i) {
        cout << dp[n][i];
    }
    
    return 0;
}

T2:拼三角形

本题难度中等,直接三重枚举会超时,需要二重循环中用二分查找最后一条边。

如果知道三边大小顺序,只要判最长边是否小于另两边之和
\(L\) 数组排序,枚举 \((L_i, L_j, L_k)\) 时,就一定有 \(L_i \leqslant L_j \leqslant L_k\)

只要 \(L_k < L_i+L_j\) 就能构成三角形

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

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<int> l(n);
    rep(i, n) cin >> l[i];
    
    sort(l.begin(), l.end());
    
    int ans = 0;
    rep(i, n) {
        for (int j = i+1; j < n; ++j) {
            int ac = j, wa = n;
            while (abs(ac-wa) > 1) {
                int wj = (ac+wa)/2;
                if (l[wj] < l[i]+l[j]) ac = wj;
                else wa = wj;
            }
            ans += ac-j;
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}