T1:两数归零

\(a_i + a_j = 0 \Leftrightarrow a_j = -a_i\),用 std::map<int, int> 来统计即可

代码实现
#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;
    map<int, int> mp;
    for (int x : a) {
        ans += mp[-x];
        mp[x]++;
    }
    
    cout << ans << '\n';
    
	return 0;
}

T2:牛奶供应(四)

\(x = p+(m-d_i)\)

显然每次应该优先购买 \(x\) 最小的那一次,这样就能保证 \(x\) 小的尽可能多买,\(x\) 大的尽可能少买
可以用 std::multiset 来维护

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

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

int main() {
    int n, m, L;
    cin >> n >> m >> L;
    
    multiset<P> s;
    rep(i, n) {
        int d, w, p;
        cin >> d >> w >> p;
        p += m-d;
        s.emplace(p, w);
    }
    
    ll ans = 0;
    while (L) {
        auto [p, w] = *s.begin();
        if (L <= w) {
            ans += (ll)L*p;
            break;
        }
        else {
            ans += (ll)w*p;
            s.erase(s.begin());
            L -= w;
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}

T3:工作安排

简单贪心

对于第 \(i\) 份任务和第 \(j\) 份任务,第 \(i\) 份任务先于第 \(j\) 份任务之前完成 \(\Leftrightarrow ~ t_if_i + (t_i+t_j) \times f_j < t_jf_j + (t_i+t_j) \times f_i \Leftrightarrow t_if_j < t_jf_i\)

按这个规则做一遍排序即可

注意开 long long

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

using namespace std;
using ll = long long;

struct node {
    int t, f;
    node() {}
    node(int t, int f): t(t), f(t) {}
    bool operator<(node& o) const {
        return (ll)t*o.f < (ll)o.t*f;
    }
};

int main() {
    int n;
    cin >> n;
    
    vector<node> ps(n);
    rep(i, n) cin >> ps[i].t >> ps[i].f;
    
    sort(ps.begin(), ps.end());
    
    ll ans = 0, now = 0;
    for (auto [t, f] : ps) {
        now += t;
        ans += now*f;
    }
    
    cout << ans << '\n';
    
    return 0;
}

T4:单词解密

dp[i] 表示将 \(s\) 的前 \(i\) 个字符转化为明文的方案数

转移方程:

如果 \(1 \leqslant s_i \leqslant 9\),则可以直接转化为 \(a \sim i\)
\(\Rightarrow\) dp[i+1] += dp[i]

如果 \(10 \leqslant \overline{s_{i-1}s_i} <= 26\),则可以将这两个字符转成 \(j \sim z\)
\(\Rightarrow\) dp[i+1] += dp[i-1]

初始化:\(dp[0] = 1\)

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

using namespace std;
using ll = long long;

//const int mod = 998244353;
const int mod = 1000000007;
struct mint {
    ll x;
    mint(ll x=0):x((x%mod+mod)%mod) {}
    mint operator-() const {
        return mint(-x);
    }
    mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += mod-a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint a) const {
        return mint(*this) += a;
    }
    mint operator-(const mint a) const {
        return mint(*this) -= a;
    }
    mint operator*(const mint a) const {
        return mint(*this) *= a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t>>1);
        a *= a;
        if (t&1) a *= *this;
        return a;
    }

    // for prime mod
    mint inv() const {
        return pow(mod-2);
    }
    mint& operator/=(const mint a) {
        return *this *= a.inv();
    }
    mint operator/(const mint a) const {
        return mint(*this) /= a;
    }
};
istream& operator>>(istream& is, mint& a) {
    return is >> a.x;
}
ostream& operator<<(ostream& os, const mint& a) {
    return os << a.x;
}

int main() {
    string s;
    cin >> s;
    int n = s.size();
    
    vector<mint> dp(n+1);
    dp[0] = 1;
    rep(i, n) {
        if (s[i] != '0') dp[i+1] += dp[i];
        if (i >= 1) {
            string t = s.substr(i-1, 2);
            if ("10" <= t and t <= "26") dp[i+1] += dp[i-1];
        }
    }
    
    cout << dp[n] << '\n';
    
    return 0;
}