2020ICPC小米 网络选拔赛第一场部分题解
比赛链接:2020ICPC小米 网络选拔赛第一场
A - Intelligent Warehouse
题目要求选择一串连续的数列,使每一个都是上一个的倍数,由于一个数可以存在很多因数,所以选择用动态规划来做。状态转移方程:
\[dp[j] = max(dp[i]) + cnt[j],j \% i = 0
\]
#include <iostream>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define N 10000000 + 10
int n, tmp, dp[N], cnt[N], ans;
int main() {
io_speed_up;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> tmp;
cnt[tmp]++;
}
for (int i = 1; i <= 10000000; ++i) {
if (!cnt[i]) {
continue;
}
dp[i] += cnt[i];
ans = max(ans, dp[i]);
for (int j = i * 2; j <= 10000000; j += i) {
dp[j] = max(dp[j], dp[i]);
}
}
cout << ans;
return 0;
}
B - Intelligent Robot
假设有一堵墙挡在必经之路上,那最短路径一定是从起点径直走向墙的端点再径直走向终点。
所以可以将题目看成是\(k\)堵墙\(2 * k\)的端点加上起点和终点共\(2 * k + 2\)个端点跑最短路。
接下来考虑建边:
如果两点之间的线段与所有墙都没有交点或者交点是墙的两个端点,则这条线段可以建边。
至于判断线段相交,较常见的就是叉乘。这里贴一个大佬的博客。
#include <iostream>
#include <cmath>
#include <queue>
#include <iomanip>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define INF 0x3f3f3f3f
#define N 610
int n, m, k;
int head[N], cnt;
double dis[N];
struct Point {
int x, y;
Point operator - (const Point &p) const {
return Point{x - p.x, y - p.y};
}
} wall[N];
struct Node {
int u;
double dis;
bool operator < (const Node &x) const {
return dis < x.dis;
}
};
struct Edge {
int v, next;
double dis;
} edge[N * N];
void addEdge(int u, int v, double dis) {
edge[++cnt].v = v;
edge[cnt].dis = dis;
edge[cnt].next = head[u];
head[u] = cnt;
}
int mul(Point p, Point q) {
int tmp = p.x * q.y - p.y * q.x;
return tmp < 0 ? -1 : tmp > 0;
}
bool judge(Point p1, Point p2, Point q1, Point q2) {
int t1 = mul(p2 - p1, q1 - p1);
int t2 = mul(p2 - p1, q2 - p1);
int t3 = mul(q2 - q1, p1 - q1);
int t4 = mul(q2 - q1, p2 - q1);
return t1 * t2 < 0 && t3 * t4 < 0;
}
bool check(Point p, Point q) {
for (int i = 1; i <= k; ++i) {
if (judge(p, q, wall[2 * i - 1], wall[2 * i])) {
return false;
}
}
return true;
}
double getDis(Point p, Point q) {
return sqrt((p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y));
}
void dijkstra() {
for (int i = 1; i <= 2 * k + 2; ++i) {
dis[i] = INF;
}
priority_queue <Node> q;
q.push(Node{2 * k + 1, 0});
dis[2 * k + 1] = 0;
while (!q.empty()) {
int u = q.top().u;
double d = q.top().dis;
q.pop();
if (d > dis[u]) {
continue;
}
for (int i = head[u]; i; i = edge[i].next) {
if (dis[edge[i].v] > dis[u] + edge[i].dis) {
dis[edge[i].v] = dis[u] + edge[i].dis;
q.push(Node{edge[i].v, dis[edge[i].v]});
}
}
}
}
int main() {
io_speed_up;
cin >> n >> m >> k;
for (int i = 1; i <= k; ++i) {
cin >> wall[i * 2 - 1].x >> wall[i * 2 - 1].y;
cin >> wall[i * 2].x >> wall[i * 2].y;
}
cin >> wall[2 * k + 1].x >> wall[2 * k + 1].y;
cin >> wall[2 * k + 2].x >> wall[2 * k + 2].y;
for (int i = 1; i <= 2 * k + 2; ++i) {
for (int j = i + 1; j <= 2 * k + 2; ++j) {
if (check(wall[i], wall[j])) {
double len = getDis(wall[i], wall[j]);
addEdge(i, j, len);
addEdge(j, i, len);
}
}
}
dijkstra();
cout << fixed << setprecision(4);
cout << dis[2 * k + 2];
return 0;
}
C - Smart Browser
按顺序对w计数,\(1\)个w有\(1\)个/\,\(n\)个w有\(2\times n-1\)个/\。
#include <iostream>
#include <string>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
int cnt, len, ans;
int main() {
string s;
cin >> s;
len = s.length();
for (int i = 0; i < len; ++i) {
if (s[i] == 'w') {
cnt++;
} else {
if (cnt == 1) {
ans += 1;
} else if (cnt > 1) {
ans += 2 * cnt - 1;
}
cnt = 0;
}
}
if (cnt == 1) {
ans += 1;
} else if (cnt > 1) {
ans += 2 * cnt - 1;
}
cout << ans;
return 0;
}
I - Walking Machine
对最外面一圈能出去的位置往里进行搜索,标识方向和搜索方向相反则代表可以走出来。
#include <iostream>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define N 1000 + 10
const int mod = 1e9 + 7;
char mat[N][N];
int n, m, ans;
bool vis[N][N];
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
void dfs(int x, int y) {
ans++;
for (int i = 0; i < 4; ++i) {
int nxtx = x + dx[i], nxty = y + dy[i];
if (nxtx >= 1 && nxtx <= n && nxty >= 1 && nxty <= m && !vis[nxtx][nxty]) {
if (i == 0 && mat[nxtx][nxty] == 'W') {
vis[nxtx][nxty] = true;
dfs(nxtx, nxty);
}
if (i == 1 && mat[nxtx][nxty] == 'S') {
vis[nxtx][nxty] = true;
dfs(nxtx, nxty);
}
if (i == 2 && mat[nxtx][nxty] == 'A') {
vis[nxtx][nxty] = true;
dfs(nxtx, nxty);
}
if (i == 3 && mat[nxtx][nxty] == 'D') {
vis[nxtx][nxty] = true;
dfs(nxtx, nxty);
}
}
}
}
int main() {
io_speed_up;
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> mat[i][j];
}
}
if (!vis[1][1] && (mat[1][1] == 'A' || mat[1][1] == 'W')) {
vis[1][1] = true;
dfs(1, 1);
}
if (!vis[1][m] && (mat[1][m] == 'D' || mat[1][m] == 'W')) {
vis[1][m] = true;
dfs(1, m);
}
if (!vis[n][1] && (mat[n][1] == 'A' || mat[n][1] == 'S')) {
vis[n][1] = true;
dfs(n, 1);
}
if (!vis[n][m] && (mat[n][m] == 'D' || mat[n][m] == 'S')) {
vis[n][m] = true;
dfs(n, m);
}
for (int i = 2; i <= m - 1; ++i) {
if (!vis[1][i] && mat[1][i] == 'W') {
vis[1][i] = true;
dfs(1, i);
}
if (!vis[n][i] && mat[n][i] == 'S') {
vis[n][i] = true;
dfs(n, i);
}
}
for (int i = 2; i <= n - 1; ++i) {
if (!vis[i][1] && mat[i][1] == 'A') {
vis[i][1] = true;
dfs(i, 1);
}
if (!vis[i][m] && mat[i][m] == 'D') {
vis[i][m] = true;
dfs(i, m);
}
}
cout << ans;
return 0;
}