目录
- BD202301 公园
- BD202302 蛋糕划分
- 解法1
- TODO 解法2
- TODO BD202303 第五维度
- TODO BD202304 流水线搭积木
- BD202305 糖果促销
不幸因为码蹄集客户端的bug,导致没法正常参与比赛,只好事后补了
BD202301 公园
样例输入:
4 4 3
1 2 8 8
1 4
2 3
3 4
4 7
2 5
5 6
6 8
7 8
样例输出:
22
首先BFS求从小度、度度熊和终点到每个点的举距离。
然后枚举每个点,求在该点会合的答案。
O(m+n)
#include<bits/stdc++.h>
using namespace std;
int xiaoValue, xiongValue, saveValue;
int xiao, xiong, aim;
int m;
const int N = 40000 + 100;
vector<int> e[N];
int dis[3][N];
void bfs(int id, int rt) {
dis[id][rt] = 0;
queue<int> q;
q.push(rt);
while (!q.empty()) {
int u = q.front();
q.pop();
for (const auto &v: e[u]) {
if (dis[id][v] > dis[id][u] + 1) {
dis[id][v] = dis[id][u] + 1;
q.push(v);
}
}
}
}
int main() {
cin >> xiaoValue >> xiongValue >> saveValue;
cin >> xiao >> xiong >> aim;
cin >> m;
for (int i = 0, x, y; i < m; i++) {
scanf("%d%d", &x, &y);
e[x].push_back(y);
e[y].push_back(x);
}
memset(dis, 0x3f, sizeof(dis));
bfs(0, xiao);
bfs(1, xiong);
bfs(2, aim);
using LL = long long;
const int mx = dis[0][0];
LL ans = LONG_LONG_MAX;
for (int u = 1; u <= aim; u++) {
if(dis[0][u]==mx || dis[1][u]==mx || dis[2][u]==mx){
continue;
}
LL now = (LL) dis[0][u] * xiaoValue + (LL) dis[1][u] * xiongValue +
(LL) dis[2][u] * (xiaoValue + xiongValue - saveValue);
ans = min(ans, now);
}
cout << (ans==LONG_LONG_MAX?-1:ans) << endl;
return 0;
}
BD202302 蛋糕划分
解法1
按位枚举横切,dp处理纵切。
dp[已划分段数][截止位置]。dp[0][0]=0,其它dp[i][j]=INF。
枚举之前的截止位置,从(已划分段数-1)和之前的截止位置和新一段若干块的最大值,对枚举得到的所有结果求最小值。
O(n^4*2^(n-1))
按说过不了,但实际能过,可能实际比较“稀疏”,所以常数比较小。
应该可以进一步预处理成O(n^3*2^(n-1))
#include<bits/stdc++.h>
using namespace std;
const int N = 15;
const int NN = 35;
int n, k;
int mp[NN][NN], s[NN][NN];
inline int getSum(int xl, int xr, int yl, int yr) {
return s[xr][yr] - s[xl - 1][yr] - s[xr][yl - 1] + s[xl - 1][yl - 1];
}
int cal(vector<int> &pos, int l, int r) { // O(n)
int mx = 0;
for (int i = 1; i < pos.size(); i++) {
mx = max(mx, getSum(pos[i - 1] + 2, pos[i] + 1, l, r)); // 0 1
}
if (!pos.empty()) {
int fst = getSum(1, pos.front() + 1, l, r);
int lst = getSum(pos.back() + 2, n, l, r);
mx = max(mx, max(fst, lst));
} else {
int all = getSum(1, n, l, r);
mx = max(mx, all);
}
return mx;
}
inline int work(vector<int> &pos, int rest) {
int dp[NN][NN];
memset(dp, 0x3f, sizeof(dp));
dp[0][0] = 0;
++rest;
for (int i = 1; i <= rest; i++) { // O(n^3)
int ed = n - (rest - i);
for (int j = i; j <= ed; j++) {
for (int p = i - 1; p < j; p++) {
if (dp[i - 1][p] < dp[i][j]) {
int now = cal(pos, p + 1, j);
dp[i][j] = min(dp[i][j], max(dp[i - 1][p], now));
}
}
// printf("dp[ %d ][ %d ] = %d\n", i, j, dp[i][j]);
}
}
return dp[rest][n];
}
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> mp[i][j];
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + mp[i][j];
}
}
int ans = 1000 * 20 * 20;
for (int i = 0; i < (1 << (n - 1)); i++) { // O(2^(n-1))
vector<int> pos;
{
for (int p = 0; (1 << p) <= i; p++) {
if (i & (1 << p)) {
pos.push_back(p);
}
}
}
if (pos.size() > k) {
continue;
}
int now = work(pos, k - pos.size());
// printf("%o: %d\n", i, now);
ans = min(ans, now);
}
cout << ans << endl;
return 0;
}
TODO 解法2
枚举横切,然后二分答案,每次划分尽可能推迟到较靠后的位置。
TODO BD202303 第五维度
TODO BD202304 流水线搭积木
BD202305 糖果促销
3
3 4
4 5
2 7
3
4
4
至少要买一颗糖果。用糖纸换的不需要买。
小心负数被除会向负无穷取整。
#include<bits/stdc++.h>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while (T--) {
int p, k;
scanf("%d%d", &p, &k);
if (k == 0) {
puts("0");
} else {
printf("%d\n", k - (k - 1) / p);
}
}
return 0;
}