C. AtCoder AAC Contest

二分答案

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

using namespace std;

void solve() {
    int a, b, c;
    cin >> a >> b >> c;
    
    auto judge = [&](int x) {
        if (a < x or c < x) return false;
        int s = (a-x) + b + (c-x);
        return s >= x;
    };
    
    int ac = 0, wa = a+1;
    while (abs(ac-wa) > 1) {
        int wj = (ac+wa)/2;
        if (judge(wj)) ac = wj; else wa = wj;
    }
    
    cout << ac << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}

实际上答案就是 \(\min\{a, c, \lfloor\frac{a+b+c}{3}\rfloor\}\)

D. Least Unbalanced

分治
每次将当前值 \(x\) 分成两半,如果 \(x\) 为奇数,就将 \(\lfloor\frac{x}{x}\rfloor\) 放在左边,\(x- \lfloor\frac{x}{x}\rfloor\) 放在右边

这种构造可以保证平衡度最多为 \(1\)
\(k\)\(2^n\) 的倍数时,最小平衡度为 \(0\),否则为 \(1\)

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

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    
    vector<int> a(1, k);
    rep(j, n) {
        vector<int> na;
        for (int x : a) {
            na.push_back(x/2);
            na.push_back(x-x/2);
        }
        a = na;
    }
    
    int u = 1;
    if (k%a.size() == 0) u = 0;
    cout << u << '\n';
    for (int x : a) cout << x << ' ';
    
    return 0;
}

E. Colinear

如果存在严格过 \(\frac{n}{2}\) 个的点,那么随机选两个点,它们都在这条直线上的概率至少是 \(\frac{1}{4}\),失败率最多为 \((1-\frac{1}{4})^{T}=(\frac{3}{4})^T\),尝试足够多的点对,失败概率极小
随机选两个点,不妨记为 \((x_1, y_1)\)\((x_2, y_2)\)

\(ax_1 + by_1 + c = 0\)
\(ax_2 + by_2 + c = 0\)

\(\Rightarrow\) \((x_1-x_2)a = (y_2-y_1)b\)
那么我们只需取 \(a = y_2-y_1\)\(b = x_1-x_2\) 即可

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

using namespace std;
using ll = long long;

struct V {
    ll x, y;
};

int main() {
    int n;
    cin >> n;
    
    vector<V> ps(n);
    rep(i, n) cin >> ps[i].x >> ps[i].y;
    
    rep(ti, 100) {
        int i = rand()%n, j = rand()%(n-1);
        if (i <= j) j++;
        
        ll a = ps[j].y - ps[i].y;
        ll b = ps[i].x - ps[j].x;
        ll c = -(a*ps[i].x + b*ps[i].y);
        
        int cnt = 0;
        rep(k, n) {
            if (a*ps[k].x + b*ps[k].y + c == 0) cnt++;
        }
        
        if (cnt*2 > n) {
            puts("Yes");
            cout << a << ' ' << b << ' ' << c << '\n';
            return 0;
        }
    }
    
    puts("No");
    
    return 0;
}

F. Eat and Ride

最短路变种
dp[i][v] 表示从点 \(v\) 开始再走 \(i\) 步时所消耗的最少燃料
注意从后往前转移

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

using namespace std;
using ll = long long;

inline void chmin(ll& a, ll b) { if (a > b) a = b; }

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<ll> w(n);
    rep(i, n) cin >> w[i];
    
    vector<vector<int>> to(n);
    rep(i, m) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        to[a].push_back(b);
        to[b].push_back(a);
    }
    
    const ll INF = 1e18;
    vector dp(n+1, vector<ll>(n, INF));
    rep(i, n) dp[i][0] = w[0]*i;
    
    for (int i = n-1; i >= 0; --i) {
        rep(v, n) {
            for (int u : to[v]) {
                chmin(dp[i][u], dp[i+1][v] + w[u]*i);
            }
        }
    }
    
    rep(v, n) cout << dp[0][v] << '\n';
    
    return 0;
}

G. Balls and Boxes

fps的入门题

第一题:ogf

\( F_a = 1 + x^A + x^{2A} + x^{3A} + \cdots \)

\( F_b = 1 + x^B + x^{2B} + x^{3B} + \cdots \)

\( F_c = 1 + x^C + x^{2C} + x^{3C} + \cdots \)

答案就是 \([x^N](F_aF_bF_c)\)

第二题:egf

\( F_a = \frac{1}{0!} \cdot 1 + \frac{1}{A!} \cdot x^A + \frac{1}{2A!} \cdot x^{2A} + \frac{1}{3A!} \cdot x^{3A} + \cdots \)

\( F_b = \frac{1}{0!} \cdot 1 + \frac{1}{B!} \cdot x^B + \frac{1}{2B!} \cdot x^{2B} + \frac{1}{3B!} \cdot x^{3B} + \cdots \)

\( F_c = \frac{1}{0!} \cdot 1 + \frac{1}{C!} \cdot x^C + \frac{1}{2C!} \cdot x^{2C} + \frac{1}{3C!} \cdot x^{3C} + \cdots \)

答案就是 \(N![x^N](F_aF_bF_c)\)

代码实现
#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;
using fps = vector<mint>;

struct modinv {
  int n; vector<mint> d;
  modinv(): n(2), d({0,1}) {}
  mint operator()(int i) {
    while (n <= i) d.push_back(-d[mint::mod()%n]*(mint::mod()/n)), ++n;
    return d[i];
  }
  mint operator[](int i) const { return d[i];}
} invs;
struct modfact {
  int n; vector<mint> d;
  modfact(): n(2), d({1,1}) {}
  mint operator()(int i) {
    while (n <= i) d.push_back(d.back()*n), ++n;
    return d[i];
  }
  mint operator[](int i) const { return d[i];}
} facts;
struct modfactinv {
  int n; vector<mint> d;
  modfactinv(): n(2), d({1,1}) {}
  mint operator()(int i) {
    while (n <= i) d.push_back(d.back()*invs(n)), ++n;
    return d[i];
  }
  mint operator[](int i) const { return d[i];}
} ifacts;
mint comb(int n, int k) {
  if (n < k || k < 0) return 0;
  return facts(n)*ifacts(k)*ifacts(n-k);
}

int main() {
    int n;
    cin >> n;
    
    vector<int> a(3);
    rep(i, 3) cin >> a[i];
    
    rep(pid, 2) {
        fps f = {1};
        rep(i, 3) {
            fps g(n+1);
            for (int j = 0; j <= n; j += a[i]) g[j] = pid==0 ? 1 : ifacts(j);
            f = convolution(f, g);
            f.resize(n+1);
        }
        mint ans = f[n] * (pid==0 ? 1 : facts(n));
        cout << ans.val() << '\n';
    }
    
    return 0;
}