D.哥三好

Solution

容易想到用 三维 加记忆化搜索得到答案,但是 ,不能开这么大的数组,考虑如何压缩数据。注意到每次花费分别为 ,不难证明对花费和金额同时做乘法除法后与原问题等价,先分别乘2,此时花费为 ,金额,再同时除以100,花费变为 ,此时金额为 。金额均满足 ,做朴素的记忆化搜索即可。

Code

#include<bits/stdc++.h>

const int mod = 1e9 + 7;
const int N = 1e5 + 5;

long long dp[205][205][205];
int table[3] = {6, 9, 15};
long long dfs(int a, int b, int c) {
    if (dp[a][b][c] != -1) {
        return dp[a][b][c];
    }
    long long res = 0;
    for (int i = 0; i < 3; i++) {
        int x = table[i];
        if (a >= x) {
            res += dfs(a - x, b, c);
        }
        if (b >= x) {
            res += dfs(a, b - x, c);
        }
        if (c >= x) {
            res += dfs(a, b, c - x);
        }
        if (res >= mod) {
            res %= mod;
        }
    }
    if (!res) {
        return dp[a][b][c] = 1;
    } else {
        return dp[a][b][c] = res;
    }
}
void solve() {
    memset(dp, -1, sizeof(dp));
    int a, b, c; std::cin >> a >> b >> c;
    a *= 2, b *= 2, c *= 2;
    a /= 100, b /= 100, c /= 100;
    std::cout << dfs(a, b, c) << '\n';
}
signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T; 
    while (T--) {
        solve();
    }
    return 0;
}

G. 永不言弃

Solution

题目给出的需要通过前置关卡才能通关后续关卡,显然可以用拓扑排序来做,关键点在于一开始要判断能否通过关卡1,随后在拓扑排序的过程中可能有的关卡暂时无法通过,可以丢到一个优先队列(最小堆)和一个 ,当 更新和获得必须道具时,可以检查优先队列和 里是否有新的节点能否加入。

Code

#include<bits/stdc++.h>

const int mod = 1e9 + 7;
const int N = 1e6 + 5;

std::pair<int, int> a[500005], benefit[50005];
std::vector<int> V[50005], G[50005];
int in[50005], mp[50005];
bool vis[50005];
void solve() {
    int n; long long s; std::cin >> n >> s;
    for (int i = 1; i <= n; i++) { 
        std::cin >> a[i].first >> a[i].second;    
    }
    for (int i = 1; i <= n; i++) {
        std::cin >> benefit[i].first >> benefit[i].second;
    }
    for (int i = 1; i <= n; i++) {
        int k; std::cin >> k;
        for (int j = 1; j <= k; j++) {
            int num; std::cin >> num;
            G[i].emplace_back(num);
            in[num]++;
        }
    }
    std::queue<int> que_topo;
    for (int i = 1; i <= n; i++) {
        if (!in[i] && i != 1) { // 永远无法开启
            std::cout << "No\n"; return ;
        }
    } 
    if (s <= a[1].first) {
        std::cout << "No\n"; return ;
    }
    que_topo.push(1);
    std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >, std::greater<std::pair<int, int> > > que_buffer;
    while (!que_topo.empty()) {
        auto now = que_topo.front(); que_topo.pop();
        if (vis[now]) continue;
        vis[now] = true;
        if (!mp[benefit[now].second]) {
            mp[benefit[now].second]++; // 拥有这个物品
            for (auto &v : V[benefit[now].second]) {
                if (!vis[v]) {
                    que_topo.push(v);
                }
            }
            V[benefit[now].second].clear();
        }
        s += benefit[now].first; // 加属性
        while (!que_buffer.empty() && s > que_buffer.top().first) {
            que_topo.push(que_buffer.top().second);
            que_buffer.pop();
        }
        for (auto &v : G[now]) {
            in[v]--;
            if (!in[v]) {
                if (mp[a[v].second]) { // 有必备道具
                    que_topo.push(v);
                } else if (s > a[v].first) { // 属性足够
                    que_topo.push(v);
                } else {
                    V[a[v].second].emplace_back(v); 
                    que_buffer.push({a[v].first, v}); // 缓冲池,存储 
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            std::cout << "No\n"; return ;
        }
    }
    std::cout << "Yes\n";
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

H.卷王之王

Solution

每次做一次加的操作相当于一次倍增(x -> 2x),考虑到 ,最多只能做 次,所以用一个优先队列每次取出要处理的序列即,注意要特判 是否为 0

Code

#include<bits/stdc++.h>

const int mod = 1e9 + 7;
const int N = 2e5 + 5;

void solve() {
    int n, m; std::cin >> n >> m;
    std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >, std::greater<std::pair<int, int> > > que;
    for (int i = 1; i <= n; i++) {
        int x; std::cin >> x;
        que.push({x, i});
    }
    std::vector<int> ans(n + 1);
    while (m--) {
        int x; std::cin >> x;
        if (x == 0) {
            continue;
        }
        std::vector<std::pair<int, int> > buffer;
        while (!que.empty() && que.top().first <= x) {
            buffer.emplace_back(que.top().first + x, que.top().second);
            que.pop();
        }
        for (auto it : buffer) {
            que.push(it);
        }
    }
    while (!que.empty()) {
        auto now = que.top(); que.pop();
        ans[now.second] = now.first;
    }
    for (int i = 1; i <= n; i++) {
        std::cout << ans[i] << " \n"[i == n];
    }
}

signed main() {
    std::cin.sync_with_stdio(false), std::cin.tie(nullptr);
    int T = 1; //std::cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}