模拟

代码实现
n, d = map(int, input().split())
s = input()
ans = s.count('.') + d
print(ans)

模拟

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

using namespace std;

int main() {
    int n, d;
    string s;
    cin >> n >> d >> s;
    
    rep(di, d) {
        for (int i = n-1; i >= 0; --i) {
            if (s[i] == '@') {
                s[i] = '.';
                break;
            }
        }
    }
    
    cout << s << '\n';
    
    return 0;
}

C. Kaiten Sushi

注意到,对于满足 \(i < j\)\(a_i < a_j\) 的有序对 \((i, j)\),如果第 \(i\) 个人可以吃掉当前的寿司,就一定轮不到第 \(j\) 个人,所以可以看出能吃当前寿司的人一定满足 \(a_i\) 单调递减,具体地,我们可以预处理出序列 \(a\) 的前缀最小值序列
然后我们就可以对序列 \(a\) 的前缀最小值序列进行二分了

代码实现
#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<int> a(n), b(m);
    rep(i, n) cin >> a[i];
    rep(i, m) cin >> b[i];
    
    partial_sum(a.cbegin(), a.cend(), a.begin(), [&](int x, int y) { return min(x, y); });
    
    rep(j, m) {
        int i = lower_bound(a.begin(), a.end(), b[j], greater<int>()) - a.begin();
        if (i == n) cout << "-1\n";
        else cout << i+1 << '\n';
    }
    
    return 0;
}

D. Keep Distance

爆搜+简单剪枝

代码实现
#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>> ans;
    auto f = [&](auto& f, vector<int> a) {
        if (a.size() == n) {
            ans.push_back(a);
            return;
        }
        
        int l = 1;
        if (a.size()) l = a.back() + 10;
        a.push_back(l);
        while (a.back()+10*(n-a.size()) <= m) {
            f(f, a);
            a.back()++;
        }
    };
    f(f, vector<int>());
    
    cout << ans.size() << '\n';
    for (auto a : ans) {
        rep(i, n) cout << a[i] << " \n"[i == n-1];
    }
    
    return 0;
}

E. Expansion Packs

期望dp

先求出每个包装里能抽出若干张稀有卡的概率
dp[i][j] 表示在一包卡中从前 \(i\) 张卡牌中抽出 \(j\) 张稀有卡的概率
\(P[j] = dp[n][j]\)

然后就是比较麻烦的棋盘游戏

f[i] 表示从已经抽出 \(i\) 张稀有卡开始的状态到抽出目标状态时所需要打开的包装的期望次数

转移方程:

\( f[i] = \left(\sum\limits_{j=0}^{i} f[i-j] \times P[j]\right) + 1 \)

简单做一下式子变形,可以得到

\( f[i] = \dfrac{\left(\sum\limits_{j=1}^i f[i-j] \times P[j]\right) + 1}{1-P[0]} \)

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

using namespace std;

int main() {
    int n, x;
    cin >> n >> x;
    
    vector<int> per(n);
    rep(i, n) cin >> per[i];
    
    vector<double> P(1, 1);
    rep(i, n) {
        vector<double> old(i+2);
        swap(P, old);
        double p = per[i]/100.;
        rep(j, i+1) {
            P[j] += old[j]*(1-p);
            P[j+1] += old[j]*p;
        }
    }
    
    vector<double> dp(x+1);
    for (int i = 1; i <= x; ++i) {
        for (int j = 1; j <= n; ++j) {
            dp[i] += dp[max(0, i-j)]*P[j];
        }
        dp[i] += 1;
        dp[i] /= 1-P[0];
    }
    
    printf("%.10f\n", dp[x]);
    
    return 0;
}

F. Falling Bars

先对每个横条按行号从大到小进行排序
然后维护满足以下功能的延迟线段树进行模拟即可

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

using namespace std;

const int INF = 1001001001;

int op(int a, int b) { return min(a, b); }
int e() { return INF; }

int mapping(int f, int x) { return min(x, f); }
int composition(int f, int g) { return min(f, g); }
int id() { return INF; }

int main() {
    int h, w, n;
    cin >> h >> w >> n;
    
    vector<tuple<int, int, int, int>> bars;
    rep(i, n) {
        int r, c, l;
        cin >> r >> c >> l;
        c--;
        bars.emplace_back(r, c, c+l, i);
    }
    
    ranges::sort(bars, greater<>());
    
    lazy_segtree<int, op, e, int, mapping, composition, id> t(vector<int>(w, h));
    
    vector<int> ans(n);
    for (auto [_, l, r, bi] : bars) {
        int x = t.prod(l, r);
        ans[bi] = x;
        t.apply(l, r, x-1);
    }
    
    rep(i, n) cout << ans[i] << '\n';
    
    return 0;
}

G. Tile Distance 3

通过旋转或反转来缩小位置关系,再进行各种分讨