2024 蓝桥杯模拟赛 2
P8840 [传智杯 #4 初赛] 报告赋分
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
for (int a, p; t; t--) {
cin >> a >> p;
if (p < 16) a -= 10;
else if (p > 20) a -= p - 20;
cout << max(0ll, a) << "\n";
}
return 0;
}
P8822 [传智杯 #3 初赛] 课程报名
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, v, m, a;
cin >> n >> v >> m >> a;
int res = 0;
for (int i = 1; i <= n; i++) {
res += v;
if (i % m == 0) v += a;
}
cout << res << "\n";
return 0;
}
P8845 [传智杯 #4 初赛] 小卡和质数
异或和为1,必定一个奇数一个偶数,偶质数只有2,因此只有2、3一对
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
for( int x , y ; t ; t -- ){
cin >> x >> y;
if( x > y ) swap( x , y);
if( x == 1 and y == 2 ) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
P8605 [蓝桥杯 2013 国 AC] 网络寻路
枚举中间的边,然后两端点所连点的乘积,就是这条边作为中间边的方案数
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
vi cnt(n + 1);
vector<pii> e(m);
for (auto &[x, y]: e)
cin >> x >> y, cnt[x]++, cnt[y]++;
int res = 0;
for (const auto &[x, y]: e)
res += (cnt[x] - 1) * (cnt[y] - 1) * 2;
cout << res << "\n";
return 0;
}
P8662 [蓝桥杯 2018 省 AB] 全球变暖
直接搜就行,给每个岛染色,然后再看剩下点有哪些颜色
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector<string> e(n);
for (auto &i: e) cin >> i;
vector g(n, vector(n, 0));
queue<pii> q;
int res = 0;
for (int x = 0; x < n; x++)
for (int y = 0; y < n; y++) {
if (e[x][y] == '.') continue;
else g[x][y] = 1;
}
vector col(n, vi(n));
for (int x = 0; x < n; x++)
for (int y = 0; y < n; y++) {
if (g[x][y] == 0) continue;
col[x][y] = x * n + y, res++;
q.emplace(x, y);
while (not q.empty()) {
auto [gx, gy] = q.front();
q.pop();
if (g[gx][gy] == 0) continue;
g[gx][gy] = 0, col[gx][gy] = col[x][y];
for (int i = 0, fx, fy; i < 4; i++) {
fx = gx + dx[i], fy = gy + dy[i];
if (fx < 0 or fy < 0 or fx >= n or fy >= n) continue;
if (g[fx][fy]) q.emplace(fx, fy);
}
}
}
for (int x = 0; x < n; x++)
for (int y = 0; y < n; y++) {
if (e[x][y] == '.') continue;
else {
g[x][y] = 1;
for (int fx, fy, i = 0; i < 4; i++) {
fx = x + dx[i], fy = y + dy[i];
if (fx < 0 or fy < 0 or fx >= n or fy >= n) continue;
if (e[fx][fy] == '.') {
g[x][y] = 0;
break;
}
}
}
}
set<int> cnt;
for (int x = 0; x < n; x++)
for (int y = 0; y < n; y++)
if (g[x][y]) cnt.insert(col[x][y]);
cout << res - cnt.size() << "\n";
return 0;
}
P8802 [蓝桥杯 2022 国 B] 出差
把点权也加到边权上,这样就是一个有向图,在有向图上求一下最短路就行
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n >> m;
vi c(n + 1);
for (int i = 1; i <= n; i++) cin >> c[i];
vector<vii> e(n + 1);
for (int u, v, w; m; m--)
cin >> u >> v >> w, e[u].emplace_back(v, w + c[v]), e[v].emplace_back(u, w + c[u]);
vi dis(n + 1, inf);
dis[1] = 0;
priority_queue<pii, vii, greater<pii>> q;
q.emplace(0, 1);
vi vis(n + 1);
while (not q.empty()) {
auto [d, x] = q.top();
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (auto &[y, w]: e[x]) {
if (vis[y] or d + w >= dis[y]) continue;
dis[y] = d + w, q.emplace(dis[y], y);
}
}
cout << dis[n] - c[n] << "\n";
return 0;
}
P8806 [蓝桥杯 2022 国 B] 搬砖
20分做法就是直接搜索就可以了
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
vii a;
int n, res = 0;
vi vis;
void dfs(int cnt, int ans) {
res = max(res, ans);
for (int i = 0; i < n; i++) {
if (vis[i]) continue;
if (a[i].first > cnt) continue;
vis[i] = 1;
dfs(min(cnt - a[i].first, a[i].second), ans + a[i].second);
vis[i] = 0;
}
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n;
a.resize(n), vis.resize(n);
for (auto &[w, v]: a) cin >> w >> v;
dfs(inf, 0);
cout << res << "\n";
return 0;
}
贪心的想法肯定是把大的砖放在下面
有两块砖\(i,j\),\(i\)必须在\(j\)的下面,\(i,j\)上面的砖总重量\(W\)
\[v_i \ge W+w_j \Rightarrow v_i-w_j\ge W\\
v_j < W+w_i \Rightarrow W >v_j-w_i\\
v_i-w_j\ge W >v_j-w_i \Rightarrow v_i-w_j>v_j-w_i\Rightarrow v_i+w_i>v_j+w_j
\]
所以可以按照\(v_i+w_i\)从大到小排序,然后就是01背包就行。但是如果是从下到上进行dp,不仅需要记录当前重量以及价值,还需要额外记录限制,并且要记录最强的限制。
所以我们可以从上到下进行dp,这样只用记录前缀重量和价值,但转移的是否判断一下转移是否合法也就是能否满足当前限制即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m;
cin >> n;
vector<pii> a(n);
for (auto &[w, v]: a) cin >> w >> v, m += w;
sort(a.begin(), a.end(), [](pii p1, pii p2) {
return p1.first + p1.second < p2.first + p2.second;
});
vi f(m + 1);
for (const auto &[w, v]: a)
for (int i = min(w + v, m); i >= w; i--)
f[i] = max(f[i], f[i - w] + v);
cout << *max_element(f.begin(), f.end()) << "\n";
return 0;
}
P8612 [蓝桥杯 2014 省 AB] 地宫取宝
数据范围太小了,直接做dp就可以
\(f[i][j][cnt][v]\)表示走到\((i,j)\)时拿了\(cnt\)个宝物且最大值是\(v\)的方案数。
然后直接\(n^4\)的枚举状态,判断转移就行,转移有两种一种取当前物品另一种是不取,实际上就是就是一个略微复杂的01背包
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
vector a(n + 1, vi(m + 1));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j], a[i][j]++;
vector f(n + 1, vector(m + 1, vector(k + 1, vi(14))));
f[1][1][0][0] = f[1][1][1][a[1][1]] = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (i == 1 and j == 1) continue;
for (int cnt = 0; cnt <= k; cnt++) {
for (int v = 0; v <= 13; v++) {
if (i - 1 >= 1) (f[i][j][cnt][v] += f[i - 1][j][cnt][v]) %= mod;
if (j - 1 >= 1) (f[i][j][cnt][v] += f[i][j - 1][cnt][v]) %= mod;
if (cnt >= k or v >= a[i][j]) continue;
if (i - 1 >= 1) (f[i][j][cnt + 1][a[i][j]] += f[i - 1][j][cnt][v]) %= mod;
if (j - 1 >= 1) (f[i][j][cnt + 1][a[i][j]] += f[i][j - 1][cnt][v]) %= mod;
}
}
}
int res = 0;
for( int v = 1 ; v <= 13 ; v ++ )
(res += f[n][m][k][v] ) %= mod;
cout << res << "\n";
return 0;
}
P8773 [蓝桥杯 2022 省 A] 选数异或
普通的线性dp
\(f[i]\)表示右端点是\(i\),一个合法区间的左端点最大是多少。\(lst[x]\)是截止目前\(x\)出现最晚的地方。所以转移就是
\[f[i] = \max(f[i-1],lst[a[i]\oplus x])
\]
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
const int inf = 1e9, INF = 1e18;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, x;
cin >> n >> m >> x;
vi f(n + 1), lst((1 << 20) + 1, -1);
for (int i = 1, a; i <= n; i++) {
cin >> a;
f[i] = max(f[i - 1], lst[a ^ x]);
lst[a] = i;
}
for( int i = 1 , l , r ; i <= m ; i ++ ){
cin >> l >> r;
if( f[r] < l ) cout << "no\n";
else cout << "yes\n";
}
return 0;
}