第45届国际大学生程序设计竞赛(ICPC)亚洲网上区域赛模拟赛部分题解

比赛链接:第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;
}
原文地址:https://www.cnblogs.com/IzumiSagiri/p/13911758.html