2017 Benelux Algorithm Programming Contest (BAPC 17) Solution
A - Amsterdam Distance
题意:极坐标系,给出两个点,求最短距离
思路:只有两种方式,取min 第一种,先走到0点,再走到终点 第二种,走到同一半径,再走过去
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define INF 0x3f3f3f3f 5 6 const double PI = acos(-1.0); 7 8 double n, m, r; 9 double n1, m1, n2, m2; 10 11 inline double work1() 12 { 13 double dis1 = r * n1 / n; 14 double dis2 = r * n2 / n; 15 return dis1 + dis2; 16 } 17 18 inline double work2() 19 { 20 double dis1 = r * (n2 - n1) / n; 21 double dis2 = fabs(m1 - m2) * r * n1 * PI/ (n * m); 22 return dis1 + dis2; 23 } 24 25 int main() 26 { 27 while (scanf("%lf%lf%lf", &m, &n, &r) != EOF) 28 { 29 scanf("%lf%lf%lf%lf", &m1, &n1, &m2, &n2); 30 if (n1 > n2) 31 { 32 swap(n1, n2); 33 swap(m1, m2); 34 } 35 double ans = INF * 1.0; 36 ans = min(ans, work1()); 37 ans = min(ans, work2()); 38 printf("%.10f\n", ans); 39 } 40 return 0; 41 }
B - Bearly Made It
留坑。
C - Collatz Conjecture
题意:给出n个数,求有多少个不同的区间gcd
思路:从头扫过去,每次扩展gcd,如果有重复的直接剪掉
因为假设扫到第i个的时候,有x个gcd 那么到第i个,这x个gcd 如果都被保留下来,那么第i个数一定要是这n个数的倍数,那么显然如果存在这样的数,那么当x > 30 的时候 早就爆 1e18 了 所以复杂度应该在 30 * (n) * log(n)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 500050 6 7 typedef long long ll; 8 9 inline ll gcd(ll a, ll b) 10 { 11 return b == 0 ? a : gcd(b, a % b); 12 } 13 14 int n; 15 ll GCD[N]; 16 ll num; 17 map<ll, int>mp; 18 19 int main() 20 { 21 while(~scanf("%d" ,&n)) 22 { 23 mp.clear(); 24 int len = 0; 25 for(int i = 1; i <= n; ++i) 26 { 27 scanf("%lld", &num); 28 for(int j = 0; j < len; ++j) 29 { 30 GCD[j] = gcd(GCD[j], num); 31 } 32 GCD[len++] = num; 33 sort(GCD, GCD + len); 34 int tmp = 0; 35 for(int i = 0; i< len; ++i) 36 { 37 mp[GCD[i]]++; 38 if(i == 0) 39 { 40 GCD[tmp++] = GCD[i]; 41 continue; 42 } 43 if(GCD[i] == GCD[i - 1]) continue; 44 else GCD[tmp++] = GCD[i]; 45 } 46 len = tmp; 47 } 48 int ans = mp.size(); 49 printf("%d\n",ans); 50 } 51 return 0; 52 }
D - Detour
题意:给出n条路,每次选择的路都不选从这条路到0的最短路径上的路,求最后选的最短路径
思路:先从1反向跑最短路,然后删边,再从0正向跑
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define M 1000010 6 #define ll long long 7 #define INFLL 0x3f3f3f3f3f3f3f3f 8 9 struct Edge 10 { 11 int to, nx, flag; 12 ll w; 13 inline Edge() {} 14 inline Edge(int to, ll w, int nx, int flag) : to(to), w(w), nx(nx), flag(flag) {} 15 }edge[M << 1]; 16 17 int head[N], pos; 18 19 inline void Init() 20 { 21 memset(head, -1, sizeof head); 22 pos = 0; 23 } 24 25 inline void addedge(int u, int v, ll w) 26 { 27 edge[++pos] = Edge(v, w, head[u], 0); head[u] = pos; 28 edge[++pos] = Edge(u, w, head[v], 0); head[v] = pos; 29 } 30 31 int n, m; 32 33 struct node 34 { 35 int to; ll w; 36 inline node() {} 37 inline node(int to, ll w) : to(to), w(w) {} 38 inline bool operator < (const node &r) const 39 { 40 return w > r.w; 41 } 42 }; 43 44 ll dist[N]; 45 int pre[N]; 46 bool used[N]; 47 48 inline void Dijkstra(int st) 49 { 50 for (int i = 0; i < n; ++i) dist[i] = INFLL, used[i] = false, pre[i] = -1; 51 dist[st] = 0; 52 priority_queue <node> q; q.emplace(st, 0); 53 while (!q.empty()) 54 { 55 int u = q.top().to; q.pop(); 56 used[u] = true; 57 for (int it = head[u]; ~it; it = edge[it].nx) 58 { 59 if (edge[it].flag) continue; 60 int v = edge[it].to; ll w = edge[it].w; 61 if (!used[v] && dist[u] + w < dist[v]) 62 { 63 dist[v] = dist[u] + w; 64 pre[v] = u; 65 q.emplace(v, dist[v]); 66 } 67 } 68 } 69 } 70 71 72 int main() 73 { 74 while (scanf("%d%d", &n, &m) != EOF) 75 { 76 ll w; Init(); 77 for (int i = 1, u, v; i <= m; ++i) 78 { 79 scanf("%d%d%lld", &u, &v, &w); 80 addedge(u, v, w); 81 } 82 Dijkstra(1); 83 if (dist[0] == INFLL) 84 { 85 puts("impossible"); 86 continue; 87 } 88 for (int i = 0; i < n; ++i) 89 { 90 for (int it = head[i]; ~it; it = edge[it].nx) 91 { 92 int v = edge[it].to; 93 if (v == pre[i]) 94 { 95 edge[it].flag = 1; 96 break; 97 } 98 } 99 } 100 Dijkstra(0); 101 if (dist[1] == INFLL) 102 { 103 puts("impossible"); 104 continue; 105 } 106 vector <int> ans; 107 int it = 1; 108 while (it != -1) 109 { 110 ans.push_back(it); 111 it = pre[it]; 112 } 113 reverse(ans.begin(), ans.end()); 114 int len = ans.size(); 115 printf("%d ", len); 116 for (int i = 0; i < len; ++i) printf("%d%c", ans[i], " \n"[i == len - 1]); 117 118 } 119 return 0; 120 }
E - Easter Eggs
留坑。
F - Falling Apart
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int n; 6 int arr[20]; 7 8 int main() 9 { 10 while (scanf("%d", &n) != EOF) 11 { 12 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 13 sort(arr + 1, arr + 1 + n); 14 int ans[2] = {0, 0}; 15 int flag = 0; 16 for (int i = n; i >= 1; --i) 17 { 18 ans[flag] += arr[i]; 19 flag ^= 1; 20 } 21 printf("%d %d\n", max(ans[0], ans[1]), min(ans[0], ans[1])); 22 } 23 return 0; 24 }
G - Going Dutch
留坑。
H - Hoarse Horses
留坑。
I - Irrational Division
题意:给出n * m 的矩形,单位边长为1,黑白交替,Alice 只能一列一列取(从左往右),Bob只能一行一行取(从下往上),取到的分数为黑块-白块,求Alice 和 Bob 的最大分差,两人操作都最优
思路:可以找一下规律,偶数行 答案是0
奇数行 奇数列 答案是1
奇数行 偶数列 行 < 列 答案是2 否则 答案是0
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int n, m; 6 7 int main() 8 { 9 while (scanf("%d%d", &n, &m) != EOF) 10 { 11 if ((n & 1) == 0) 12 { 13 puts("0"); 14 continue; 15 } 16 if ((m & 1)) 17 { 18 puts("1"); 19 continue; 20 } 21 puts(n < m ? "2" : "0"); 22 } 23 return 0; 24 }
J - Jumping Choreography
留坑。
K - King of the Waves
题意:给出n个人的胜负关系,打擂台赛,求最后0胜利,给出上场顺序
思路:输出DFS序
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 1010 6 7 int n; 8 int tot = 0; 9 int dep[N]; 10 char mp[N][N]; 11 int ans[N]; 12 13 inline void DFS(int pos, int cnt) 14 { 15 dep[pos] = cnt; 16 ans[++tot] = pos; 17 for(int i = 1; i <= n; ++i) 18 { 19 if(mp[pos][i] == '1' && !dep[i]) 20 { 21 DFS(i, cnt + 1); 22 } 23 } 24 } 25 26 int main() 27 { 28 while(~scanf("%d", &n)) 29 { 30 tot = 0; 31 memset(dep, 0 , sizeof dep); 32 for(int i = 1; i <= n; ++i) 33 { 34 for(int j = 1; j <= n; ++j) 35 { 36 scanf(" %c", &mp[i][j]); 37 } 38 } 39 DFS(1, 1); 40 if(tot != n) 41 { 42 puts("impossible"); 43 } 44 else 45 { 46 for(int i = n; i >= 1; --i) 47 { 48 printf("%d%c", ans[i] - 1, " \n"[i == 1]); 49 } 50 } 51 } 52 return 0; 53 }
L - Lemonade Trade
题意:给出n个兑换关系,刚开始有1l pink 最后想换到blue 要依次换,可以选择换和不换
思路:O(n) 扫一下,记录在这之前被兑换的颜色饮料最多能被换到多少 然后取max 注意 不能直接乘法,取log 再取e的幂次
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 7 const int INF = 0x3f3f3f3f; 8 const double EI = exp(1.0); 9 10 int cnt; 11 map<string, int >mp; 12 double ans[N]; 13 14 inline void init() 15 { 16 mp.clear(); 17 cnt = 1; 18 mp["pink"] = cnt++; 19 mp["blue"] = cnt++; 20 ans[1] = log(1.0); 21 ans[2] = -INF * 1.0; 22 } 23 24 int n; 25 string a, b; 26 double w; 27 28 int main() 29 { 30 ios::sync_with_stdio(false); 31 cin.tie(0);cout.tie(0); 32 while(cin >> n) 33 { 34 init(); 35 for(int i = 1; i <= n; ++i) 36 { 37 cin >> a >> b >> w; 38 if(mp[a] == 0) 39 { 40 mp[a] = cnt++; 41 ans[mp[a]] = -INF * 1.0; 42 } 43 if(mp[b] == 0) 44 { 45 mp[b] = cnt++; 46 ans[mp[b]] = -INF * 1.0; 47 } 48 int id1 = mp[a], id2 = mp[b]; 49 ans[id1] = max(ans[id1], ans[id2] + log(w)); 50 } 51 ans[2] = pow(EI, ans[2]); 52 ans[2] = min(ans[2], 10.0); 53 cout << setiosflags(ios::fixed) << setprecision(10) << ans[2] << endl; 54 } 55 return 0; 56 }
M - Manhattan Mornings
题意:给出n个点,起始点和终点,求从起始点到终点的最短路径,最多经过多少点
思路:先排序,固定一个轴,再求最长上升子序列
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 6 int n; 7 8 struct node 9 { 10 int x, y; 11 inline void scan() 12 { 13 scanf("%d%d", &x, &y); 14 } 15 inline bool operator < (const node &r) const 16 { 17 return x < r.x || x == r.x && y < r.y; 18 } 19 }point[N], st, ed; 20 21 int arr[N], brr[N]; 22 23 inline int DP1(int n) 24 { 25 if (n == 0) return 0; 26 int i, len, pos; 27 brr[1] = arr[1]; 28 len = 1; 29 for (int i = 2; i <= n; ++i) 30 { 31 if (arr[i] >= brr[len]) 32 { 33 len = len + 1; 34 brr[len] = arr[i]; 35 } 36 else 37 { 38 int pos = upper_bound(brr + 1, brr + 1 + len, arr[i]) - brr; 39 brr[pos] = arr[i]; 40 } 41 } 42 return len; 43 } 44 45 inline bool cmp (node a, node b) 46 { 47 return a.x > b.x || a.x == b.x && a.y < b.y; 48 } 49 50 int main() 51 { 52 while (scanf("%d", &n) != EOF) 53 { 54 st.scan(); ed.scan(); 55 for (int i = 1; i <= n; ++i) 56 point[i].scan(); 57 if (st.x > ed.x) swap(st, ed); 58 if (st.y < ed.y) 59 { 60 sort(point + 1, point + 1 + n); 61 int cnt = 0; 62 for (int i = 1; i <= n; ++i) 63 { 64 if (point[i].x >= st.x && point[i].x <= ed.x && point[i].y >= st.y && point[i].y <= ed.y) 65 arr[++cnt] = point[i].y; 66 } 67 printf("%d\n", DP1(cnt)); 68 } 69 else 70 { 71 sort(point + 1, point + 1 + n, cmp); 72 int cnt = 0; 73 for (int i = 1; i <= n; ++i) 74 { 75 if (point[i].x >= st.x && point[i].x <= ed.x && point[i].y >= ed.y && point[i].y <= st.y) 76 arr[++cnt] = point[i].y; 77 } 78 printf("%d\n", DP1(cnt)); 79 } 80 } 81 return 0; 82 }