C. Dislike Foods

可以先建立使用食材 \(x\) 的料理列表
同时维护每种料理中当前不能吃的食材数
然后按顺序模拟即可

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

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<int>> menuList(n);
    vector<int> cnt(m);
    rep(i, m) {
        int k;
        cin >> k;
        cnt[i] = k;
        rep(j, k) {
            int a;
            cin >> a;
            --a;
            menuList[a].push_back(i);
        }
    }
    
    int ans = 0;
    rep(i, n) {
        int b;
        cin >> b;
        --b;
        for (int j : menuList[b]) {
            cnt[j]--;
            if (cnt[j] == 0) ans++;
        }
        cout << ans << '\n';
    }
    
    return 0;
}

D. Line Crossing

正难则反
直线不相交意味着它们平行,因此只需知道每种斜率的直线数量即可。
如果将整体旋转使点 \(A\) 和点 \(B\) 处于水平位置,可以发现 \(A+B\) 相同是直线平行的充要条件!

image

代码实现
#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, m;
    cin >> n >> m;
    
    ll ans = (ll)m*(m-1)/2;
    vector<int> cnt(n);
    rep(i, m) {
        int a, b;
        cin >> a >> b;
        int x = (a+b)%n;
        ans -= cnt[x];
        cnt[x]++;
    }
    
    cout << ans << '\n';
    
    return 0;
}

E. Payment Required

状压dp
dp[i][S] 表示剩下 \(i\) 元时,从已通过的题的集合 \(S\) 的状态开始的期望得分的最大值

代码实现
#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, x;
    cin >> n >> x;
    
    vector<tuple<int, int, double>> ps;
    rep(i, n) {
        int s, c, p;
        cin >> s >> c >> p;
        ps.emplace_back(s, c, p/100.);
    }
    
    int n2 = 1<<n;
    vector dp(x+1, vector<double>(n2));
    rep(i, x+1)rep(s, n2) {
        rep(j, n) {
            if (s>>j&1) continue;
            auto [score, c, p] = ps[j];
            if (c > i) continue;
            double now = dp[i-c][s]*(1-p) + (dp[i-c][s|1<<j]+score)*p;
            dp[i][s] = max(dp[i][s], now);
        }
    }
    
    double ans = dp[x][0];
    printf("%.10f\n", ans);
    
    return 0;
}

F. Path to Integer

折半搜索

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

using namespace std;
using ull = unsigned long long;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector a(n, vector<int>(n));
    rep(i, n)rep(j, n) cin >> a[i][j];
    
    auto enumPath = [&]() {
        vector<vector<ull>> res(n);
        auto dfs = [&](auto& f, int i, int j, ull x) -> void {
            if (i+j == n-1) {
                res[i].push_back(x);
                return;
            }
            x = x*10+a[i][j];
            f(f, i+1, j, x);
            f(f, i, j+1, x);
        };
        dfs(dfs, 0, 0, 0);
        return res;
    };
    
    auto ss = enumPath();
    rep(i, n) ranges::reverse(a[i]);
    ranges::reverse(a);
    auto ts = enumPath();
    ranges::reverse(ts);
    
    ull ans = 0;
    auto f = [&](vector<ull> s, vector<ull> t, int d) {
        ull ten = 1;
        rep(i, n) ten = ten*10%m;
        for (ull& x : s) x = (x%m * ten)%m;
        
        for (ull& x : t) {
            ull y = x; x = d;
            rep(i, n-1) {
                x = (x*10 + y%10)%m;
                y /= 10;
            }
        }
        
        ranges::sort(s);
        ranges::sort(t);
        for (ull x : s) {
            int i = ranges::lower_bound(t, m-x)-t.begin();
            if (i) ans = max(ans, x+t[i-1]);
            ans = max(ans, (x+t.back())%m);
        }
    };
    rep(i, n) f(ss[i], ts[i], a[n-1-i][i]);
    
    cout << ans << '\n';
    
    return 0;
}

G. Sum of Prod of Mod of Linear

类欧