比赛链接:第45届国际大学生程序设计竞赛(ICPC)亚洲网上区域赛模拟赛
D - Pokemon Ultra Sun
期望DP,由于不存在无穷次数,所以可以正向递推。
#include <iostream>
#include <iomanip>
using namespace std;
double dp[3010][3010], p;
int t, hp1, hp2, w;
int main() {
cin >> t;
cout << fixed << setprecision(6);
while (t--) {
cin >> hp1 >> hp2 >> w >> p;
hp1 = hp1 / w + !(hp1 % w == 0);
hp2 = hp2 / w + !(hp2 % w == 0);
for (int i = 0; i <= hp1; ++i) {
dp[i][0] = 0;
}
for (int i = 0; i <= hp2; ++i) {
dp[0][i] = 0;
}
for (int i = 1; i <= hp1; ++i) {
for (int j = 1; j <= hp2; ++j) {
dp[i][j] = p * dp[i][j - 1] + (1 - p) * dp[i - 1][j] + 1;
}
}
cout << dp[hp1][hp2] << endl;
}
return 0;
}
E - Eat Walnuts
区间DP模板题。
#include <iostream>
#include <cstring>
using namespace std;
int a[110];
long long dp[110][110];
int n;
int main() {
while (cin >> n) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (j == i + 1) {
dp[i][j] = 0;
} else {
dp[i][j] = 0x3f3f3f3f;
}
}
}
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
for (int len = 2; len <= n - 1; ++len) {
for (int i = 1; i <= n - len; ++i) {
int j = i + len;
for (int k = i + 1; k < j; ++k) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + (a[i] + a[k] + a[j]) * (a[i] + a[k] + a[j]));
}
}
}
cout << dp[1][n] << endl;
}
return 0;
}
H - Nuclear launch detected
设(dp[i][j])为第(i)个士兵在时间为(j)时到达的情况下存活的士兵数量,则状态转移方程:
[dp[i][j] = max(dp[i - 1][(j + H - t_i) \% H], dp[i - 1][(j + H - t_i + 1) \% H])
]
[dp[i][j] = dp[i][j] + 1,L <= j <= R
]
由于每个士兵只与上一个士兵的情况有关,所以可以优化空间。
#include <iostream>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int n, h, l, r, t, ans;
int dp[2][210];
int main() {
io_speed_up;
cin >> n >> h >> l >> r;
for (int i = 0; i < h; ++i) {
dp[0][i] = -0x3f3f3f3f;
}
dp[0][0] = 0;
int p = 0;
for (int i = 1; i <= n; ++i) {
p ^= 1;
cin >> t;
for (int j = 0; j < h; ++j) {
dp[p][j] = max(dp[p ^ 1][(j + h - t) % h], dp[p ^ 1][(j + h - t + 1) % h]);
if (j >= l && j <= r) {
dp[p][j]++;
}
}
}
for (int i = 0; i < h; ++i) {
ans = max(ans, dp[p][i]);
}
cout << ans;
return 0;
}
I - Character Wheels
用一个数组来存储每一圈顺时针转动(90°)的次数,由于(360°)为一圈,所以若最后的结果为负数,则一直加(4)直至为正数;若为正数,则对(4)取模。
对每一格((i,j))获取其所在的圈的序号,由于第(1)圈的每个点的横坐标或纵坐标都有(1)或(n),第(2)圈的每个点的横坐标或纵坐标都有(2)或(n-1),以此类推。所以取横坐标和纵坐标中较小者记为(x),较大者记为(y),取(x)与(1)的差、(n)与(y)的差,前者差值小则所在圈序号为(x),否则为(n + 1 - y)。
根据序号获取所在圈的转动情况,再通过转动的角度分(0°)、(90°)、(180°)、(270°)四种情况,获取相应位置的字符输出。
#include <iostream>
using namespace std;
char mat[55][55], act;
int num, t, r[55], n, m;
int get(int x, int y) {
int minn = min(x, y), maxn = max(x, y);
maxn = n + 1 - maxn;
return min(minn, maxn);
}
void print() {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
num = get(i, j);
t = r[num];
if (t == 1) {
cout << mat[n + 1 - j][i];
} else if (t == 2) {
cout << mat[n + 1 - i][n + 1 - j];
} else if (t == 3) {
cout << mat[j][n + 1 - i];
} else {
cout << mat[i][j];
}
}
cout << endl;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> mat[i][j];
}
}
cin >> m;
for (int i = 1; i <= m; ++i) {
cin >> act;
if (act == 'L') {
cin >> num >> t;
r[num] -= t;
while (r[num] < 0) {
r[num] += 4;
}
} else if (act == 'R') {
cin >> num >> t;
r[num] += t;
r[num] %= 4;
} else {
print();
}
}
return 0;
}