solved
A
B
C
D
E
F
G
H
I
J
K
L
M
6 / 13
·
O
·
Ø
·
·
O
·
Ø
·
·
Ø
O
O:比赛时通过
Ø:赛后通过
!:比赛时尝试了未通过
·:比赛时未尝试
比赛链接
B. Mine Sweeper II
solved by lllllan. 2:05(+1)
题意 在一个n ∗ m n*m n ∗ m 的扫雷地图中,‘X X X ’表示地雷‘. . . ’表示没有地雷,没有地雷的方格上的数值为四周八个方格中含地雷的个数。现给出两个n ∗ m n*m n ∗ m 扫雷的地图,要求将第二个地图通过不多于n ∗ m / 2 n*m/2 n ∗ m / 2 的操作次数【每次操作可将‘X X X ’更改为‘. . . ’,或将’. . . ‘更改为’X X X ‘】,使得变换后的地图中的权值和与第一个地图相等,输出变换后的地图。
题解 操作次数刚好限制为地图方格个数的一半,然后考虑极端情况,两个地图完全一致,权值和必然相同;两个地图完全相反,权值和也相同。所以只要数出两个地图不同方格的个数,考虑将第二地图变换成和第一地图完全一致还是完全相反。最后特判1 ∗ 1 1*1 1 ∗ 1 的地图即可。
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <bits/stdc++.h> using namespace std ;typedef long long ll;const int N = 1e3 + 10 ;int n, m;char a[N][N], b[N][N];int main () { scanf ("%d%d" , &n, &m); for (int i = 1 ; i <= n; ++i) { scanf ("%s" , a[i] + 1 ); } int cnt = 0 ; for (int i = 1 ; i <= n; ++i) { scanf ("%s" , b[i] + 1 ); for (int j = 1 ; j <= m; ++j) { if (a[i][j] != b[i][j]) cnt++; } } int flag = 1 ; if (cnt > (n * m / 2 )) flag = 0 ; if (n == 1 && m == 1 ) { printf ("%c\n" , b[1 ][1 ]); return 0 ; } if (flag) { for (int i = 1 ; i <= n; ++i) { printf ("%s\n" , a[i] + 1 ); } } else { for (int i = 1 ; i <= n; ++i) { for (int j = 1 ; j <= m; ++j) { printf ("%c" , a[i][j] == '.' ? 'X' : '.' ); } printf ("\n" ); } } return 0 ; }
D. Walker
Solved By Sstee1XD. (-)
题意 给你一条坐标从0 0 0 开始的水平线,再给你两个点各自的横坐标和速度,每个点可以任意移动,问最短的时间让两个点遍历完整条线段。
题解 分类讨论,合并情况后发现可以分成三种情况。
让一个点走完全程
两个点往对方的的方向走(对穿),走到尽头
两个点各自走完自己的线段,在中间相遇。其中每个点又有两种情况,可以先走中间,或者先走到自己这边的尽头。
对于前两种情况可以直接求,第三种情况不好确定相遇点,所以考虑二分时间,对于两个点都选择能让自己多走中间线段的方案,相加判断长度。
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <bits/stdc++.h> using namespace std ;#define double long double #define endl "\n" #define dbg(x...) do { cout << #x << " -> "; err(x); } while (0) void err () { cout << endl ; }template <class T , class ... Ts >void err (const T& arg, const Ts&... args) { cout << arg << ' ' ; err(args...); } template <class T > inline void read (T &x) { int f = 0 ; x = 0 ; char ch = getchar(); for (; !isdigit (ch); ch = getchar()) f |= (ch == '-' ); for (; isdigit (ch); ch = getchar()) x = x * 10 + ch - '0' ; if (f) x = -x; } typedef long long ll;const int inf = 0x3f3f3f3f ;const double eps = 1e-11 ;double tot, p1, p2, v1, v2;bool sgn (double x, double y) { return fabs (y - x) <= eps; } bool check (double t) { double d1 = max((t - p1 / v1) * v1 / 2 , (t - 2 * p1 / v1) * v1); double d2 = max((t - (tot - p2) / v2) * v2 / 2 , (t - 2 * (tot - p2) / v2) * v2); if (d1 < 0 || d2 < 0 ) return false ; return d1 + d2 >= p2 - p1; } void solve () { cin >> tot >> p1 >> v1 >> p2 >> v2; if (p2 < p1) swap(p1, p2), swap(v1, v2); double ans = inf; ans = min(ans, (min(p1, tot - p1) + tot) / v1); ans = min(ans, (min(p2, tot - p2) + tot) / v2); ans = min(ans, max((tot - p1) / v1, p2 / v2)); double l = 0 , r = inf, mid; while (!sgn(l, r)) { mid = (l + r) / 2 ; if (check(mid)) r = mid; else l = mid; } ans = min(ans, mid); cout << ans << endl ; } int main () { ios::sync_with_stdio(false ); cin .tie(nullptr );cout .tie(nullptr ); cout << fixed << setprecision(20 ); int _T = 1 ; cin >> _T; while (_T--) solve(); }
G. Fibonacci
solved by Tryna. 0:16(+2)
题意 定义g ( x , y ) g(x, y) g ( x , y ) ,当x ⋅ y x ·y x ⋅ y 为偶数时g ( x , y ) = 1 g(x,y) = 1 g ( x , y ) = 1 ,求$$\sum_{i = 1}^{n}\sum_{j = i + 1}^{n}g(f_i, f_j)$$f f f 为斐波那契数列
题解 答案为( n − 1 ) ∗ n − ( 2 ∗ ( n / 3 ) + n M o d 3 ) ∗ ( ( 2 ∗ ( n / 3 ) + n M o d 3 − 1 ) ) 2 \frac{(n - 1) * n - (2 * (n / 3) + n Mod 3) * ((2 * (n / 3) + nMod 3 - 1))}{2} 2 ( n − 1 ) ∗ n − ( 2 ∗ ( n / 3 ) + n M o d 3 ) ∗ ( ( 2 ∗ ( n / 3 ) + n M o d 3 − 1 ) )
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 #include <bits/stdc++.h> using namespace std ;typedef long long ll;ll n; int main () { scanf ("%lld" , &n); ll ans = (n - 1 ) * n / 2 ; ll cnt = (2 * (n / 3 ) + n % 3 ); ll sum = cnt * (cnt - 1 ) / 2 ; printf ("%lld\n" , ans - sum); return 0 ; }
I. Sky Garden
solved by Tryna.(-)
题意 给出n个同心圆,每个圆被等分成2 m 2m 2 m 份,求每个点到其他点最短距离之和
题解 比赛的时候写到这题没时间了,然后赛后自己花了两个小时写出来了。这题的关键在于求出一个圆上每个点到其他点的最短距离和。想了一下本来想通过找规律来找到这个答案的,后来发现有点难实现,看了一下数据范围,发现可以O ( n 2 ) O(n^2) O ( n 2 ) 来算出答案。对于一个点,它有两种方案,一种是走两条半径,另外一种是走圆弧。求出一个圆上所有点到其他点的最短距离和后,这个圆上的点要想到外面的大圆上,他至少需要经过R R R (大圆的半径) - r r r (小圆的半径)的距离,想要距离最短,必须要走小圆的圆弧。可以发现小圆上的一个点到大圆上所有点的距离就是之前算出来的小圆上每个点到其他点的最短距离和加上2 m ( R − r ) 2m(R - r) 2 m ( R − r ) ,知道了这些接下来随便乱搞一下就出来了,注意要特判m = 1 m = 1 m = 1 的情况,因为此时圆心是没有交点的。代码写的比较长。
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <bits/stdc++.h> using namespace std ;#define eps 1e-8 const double pi = acos (-1.0 );double n, m;int main () { scanf ("%lf %lf" , &n, &m); if (m == 1 ){ double result = n * (n + 1 ); for (int i = 1 ; i <= n; i++){ for (int j = i + 1 ; j <= n; j++) result += 4 * j; } printf ("%.10f\n" , result); return 0 ; } double ans = 2 * m * (n * (n + 1 ) / 2 ); double c1 = 0 , angle = 1 / (2 * m), sum = 0 ; for (int i = 1 ; i <= 2 * m; i++){ angle = 1.0 / (2 * m); for (int j = i + 1 ; j <= 2 * m; j++){ if (i == 1 ){ if (angle - 0.5 > eps) c1 += min((double )2 , 2 * (1 - angle) * pi); else c1 += min((double )2 , 2 * angle * pi); angle += 1.0 / (2 * m); } else { if (angle - 0.5 > eps){ sum += min((double )2 , (1 - angle) * 2 * pi); } else sum += min((double )2 , 2 * angle * pi); angle += 1.0 / (2 * m); } } } sum += c1; for (int i = 1 ; i <= n; i++){ double cnt = i * sum; for (int j = i + 1 ; j <= n; j++) cnt += 2 * m * (2 * m * (j - i) + c1 * i); ans += cnt; } printf ("%.10f\n" , ans); return 0 ; }
L. Traveling in the Grid World
Solved By Sstee1XD. (-)
题意 给你一个n行m列的方格,左上角为( 0 , 0 ) (0, 0) ( 0 , 0 ) 点。现在要从( 0 , 0 ) (0, 0) ( 0 , 0 ) 点走到( n , m ) (n, m) ( n , m ) 点,走的规则如下:
若两点之间不存在其他的整点,则能直接走,否则不能走
任意两次路线的斜率应该不同
问你要走的最短距离是多少。
题解 显然,当g c d ( n , m ) = 1 gcd(n, m) = 1 g c d ( n , m ) = 1 时,直接输出。其余情况,不会证明,瞎猜一下要转一次得到最优答案。此时我们发现越往下面找答案会越大(三角形两边之和大于第三边),所以找到第一个点后就b r e a k break b r e a k ,最后输出最小的答案。
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <bits/stdc++.h> using namespace std ;#define endl "\n" #define dbg(x...) do { cout << #x << " -> "; err(x); } while (0) void err () { cout << endl ; }template <class T , class ... Ts >void err (const T& arg, const Ts&... args) { cout << arg << ' ' ; err(args...); } template <class T > inline void read (T &x) { int f = 0 ; x = 0 ; char ch = getchar(); for (; !isdigit (ch); ch = getchar()) f |= (ch == '-' ); for (; isdigit (ch); ch = getchar()) x = x * 10 + ch - '0' ; if (f) x = -x; } typedef long long ll;const int inf = 0x3f3f3f3f ;ll gcd (ll a, ll b) { return a == 0 ? b : gcd(b % a, a); } double getDis (double x, double y) { return sqrt (x * x + y * y); } ll n, m; double k;void solve () { scanf ("%lld %lld" , &n, &m); if (gcd(n, m) == 1 ) { printf ("%.10f\n" , getDis(n, m)); return ; } k = (double )m / (double )n; double minn = n + m; for (ll _x = 0 ; _x < n; ++_x) { ll _y = k * _x + 1 ; for (; _y <= m; ++_y) { if (gcd(_x, _y) != 1 ) continue ; if (n * _y == m * _x) continue ; minn = min(minn, getDis(_x, _y) + getDis(n - _x, m - _y)); break ; } } printf ("%.10f\n" , minn); } int main () { int _T = 1 ; scanf ("%d" , &_T); while (_T--) solve(); return 0 ; }
M. Gitignore
solved by lllllan. 4:36(+1)
题意 有N N N 个可折叠的文件和M M M 个不可折叠的文件,考虑N N N 个可折叠的文件最后必须显示多少个。【比如a / b a/b a / b 和a / c a/c a / c 可折叠为a / a/ a / ,最后只需显示一个文件即可】
题解 先对M M M 个不可折叠的文件进行前缀标记【比如a / b / c / d a/b/c/d a / b / c / d 文件是不可折叠的,则用m a p map m a p 记录下a a a 、a / b a/b a / b 和 a / b / c a/b/c a / b / c 均为不可折叠】。然后再遍历前N N N 个可折叠的文件,对必须显示的文件进行计数,可以折叠成已有显示的文件进行忽略。
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <bits/stdc++.h> using namespace std ;int _T, n, m;map <string , int > mp, vis;void run () { string s[100 ]; mp.clear(), vis.clear(); cin >> n >> m; for (int i = 1 ; i <= n; ++i) { cin >> s[i]; } for (int i = 1 ; i <= m; ++i){ string str; cin >> str; int len = str.size(); for (int j = 0 ; j < len; ++j) { if (str[j] == '/' ) { mp[str.substr(0 , j)] = 1 ; } } } int ans = 0 ; for (int i = 1 ; i <= n; ++i) { int flag = 1 ; int len = s[i].size(); for (int j = 0 ; j <= len; ++j) { if (s[i][j] == '/' ) { string tem = s[i].substr(0 , j); if (mp[tem]) flag = 1 ; else { if (vis[tem]) flag = 0 ; vis[tem] = 1 ; break ; } } } ans += flag; } cout << ans << endl ; } int main () { cin >> _T; while (_T--) run(); return 0 ; }