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;
} 
京公网安备 11010502036488号