solved
A
B
C
D
E
F
G
H
I
J
K
L
M
7 / 13
O
·
·
Ø
·
·
Ø
·
O
O
Ø
·
Ø
O:比赛时通过
Ø:赛后通过
!:比赛时尝试了未通过
·:比赛时未尝试
比赛链接
A. Adrien and Austin
solved by Sstee1XD & Tryna. 0:36(+3)
题意 n n n 个石子,每个石子从1 1 1 到n n n 编号,每次可以取1 1 1 -k k k 个连续的石子,问谁先取完。
题解 :我们特判n n n 为0 0 0 和k k k 为1 1 1 的情况,对于其余情况,先手都可以做出相应的选择达到必胜态。
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 #include <bits/stdc++.h> using namespace std ;int n, k;int main () { scanf ("%d %d" , &n, &k); if (n == 0 ) puts ("Austin" ); else if (k == 1 && n % 2 == 0 ) puts ("Austin" ); else puts ("Adrien" ); return 0 ; }
D - Country Meow
solved by Tryna. (-)
题意: 求覆盖了所有点的最小球半径
题解: 裸题,跑一边模拟退火,代码中更新pos值的时候理解了很久。总的来说就是当前温度越高,向最远点移动的幅度越大,当前温度越低,向最远点移动的幅度越小
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 #include <bits/stdc++.h> using namespace std ; #define inf 0x3f3f3f3f #define eps 1e-8 const int maxn = 110 ;const double startT = 100000 ;struct Point { double x, y, z; }P[maxn]; double Dist (Point a, Point b) { return sqrt ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z)); } int n;double SA () { double delta = 0.98 , T = startT, ans = inf; Point pos = {0 , 0 , 0 }; while (T > eps){ Point maxP = P[1 ]; for (int i = 2 ; i <= n; i++){ if (Dist(pos, P[i]) > Dist(pos, maxP)) maxP = P[i]; } ans = min(ans, Dist(pos, maxP)); pos.x += (maxP.x - pos.x) * T / startT; pos.y += (maxP.y - pos.y) * T / startT; pos.z += (maxP.z - pos.z) * T / startT; T *= delta; } return ans; } int main () { scanf ("%d" , &n); for (int i = 1 ; i <= n; i++) scanf ("%lf %lf %lf" , &P[i].x, &P[i].y, &P[i].z); printf ("%.15f\n" , SA()); return 0 ; }
G - Pyramid
solved by Tryna. (-)
题意: 计算等边三角形的个数
题解: 打表找规律,打表的思路就是把三角形放入坐标系中,O(n^3)暴力枚举每个顶点,如果三条边长度相同就计数。
打完表发现前几个数是这样的: 0 1 5 15 35 70 126 210
下面的方法将会用到这里的知识:差分的应用
所以我们对上面那个数列不断差分。
0 1 5 15 35 70 126 210
1 4 10 20 35 56 84
3 6 10 15 21 28
3 4 5 6 7
1 1 1 1
0 0 0
所以前n项和
S ( n ) = 1 C n + 1 2 + 3 C n + 1 3 + 3 C n + 1 4 + 1 C n + 1 5 S(n) = 1C_{n+1} ^ 2 + 3C_{n+1} ^ 3 + 3C_{n+1} ^ 4 + 1C_{n+1} ^ 5
S ( n ) = 1 C n + 1 2 + 3 C n + 1 3 + 3 C n + 1 4 + 1 C n + 1 5
化简得
S ( n ) = n ∗ ( n + 1 ) ∗ ( n + 2 ) ∗ ( n + 3 ) ∗ ( n + 4 ) 120 S(n) = \frac{n*(n+1)*(n+2)*(n+3)*(n+4)}{120}
S ( n ) = 1 2 0 n ∗ ( n + 1 ) ∗ ( n + 2 ) ∗ ( n + 3 ) ∗ ( n + 4 )
所以第n项$$f(n) = S(n) - S(n-1)$$
化简得:
f ( n ) = n ∗ ( n + 1 ) ∗ ( n + 2 ) ∗ ( n + 3 ) 24 f(n) = \frac{n*(n+1)*(n+2)*(n+3)}{24}
f ( n ) = 2 4 n ∗ ( n + 1 ) ∗ ( n + 2 ) ∗ ( n + 3 )
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 #include <cstdio> #include <vector> #include <map> #include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cmath> #include <iomanip> #include <queue> using namespace std ; #define inf 0x3f3f3f3f #define ll long long #define eps 1e-10 #define endl "\n" const int maxn = 1000010 ;const int mod = 1e9 + 7 ;const double pi = acos (-1.0 );int moven2[10 ][5 ] = {{1 , 0 , 0 }, {-1 , 0 , 0 }, {0 , 1 , 0 }, {0 , -1 , 0 }, {0 , 0 , 1 }, {0 , 0 , -1 }}; int moven1[10 ][5 ] = {{1 , 0 }, {-1 , 0 }, {0 , 1 }, {0 , -1 }};int quick_power (ll n, ll k) { int ans=1 ; while (k){ if (k&1 ){ ans=(ans*n)%mod; } n=n*n%mod; k>>=1 ; } return ans%mod; } int t;ll n; int main () { scanf ("%d" , &t); while (t--){ scanf ("%lld" , &n); ll ans = quick_power((ll)24 , mod - 2 ); ans = ans * n % mod * (n + 1 ) % mod * (n + 2 ) % mod * (n + 3 ) % mod; printf ("%lld\n" , ans); } return 0 ; }
I. Magic Potion
solved by lllllan. 01:26(+)
题意: n个英雄和m个怪兽,每个英雄都有对应的可以击败的怪兽并且只能选择其中一只。现有k瓶药水,每个英雄最多喝一瓶然后可以多击败一只怪兽。问最多可以击败多少只怪兽。
题解: 相比最经典的匹配问题,一个男朋友对应一个女朋友,现在可以一夫多妻了【不是】。又不像多重匹配那么麻烦,每个英雄最多也只能击败两只怪兽而已。所以就是简单跑两次匹配就可以了。 然后注意有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 #include <bits/stdc++.h> using namespace std ;#define _for(i, a, b) for(int i = (a); i <= (b); ++i) const int N = 510 ;int sum;int n, m, k, t, x;int vis[N], match[N];vector <int > G[N];bool dfs (int u) { for (auto v : G[u]) { if (match[v] == u) continue ; if (!vis[v]) { vis[v] = 1 ; if (!match[v] || dfs(match[v])) { match[v] = u; return true ; } } } return false ; } void solve () { memset (match, 0 , sizeof match); _for(i, 1 , n) { memset (vis, 0 , sizeof vis); if (dfs(i)) sum++; } for (int i = 1 ; i <= n && k; i++) { memset (vis, 0 , sizeof vis); if (dfs(i)) sum++, k--; } } int main () { scanf ("%d%d%d" , &n, &m, &k); _for(i, 1 , n) { scanf ("%d" , &t); while (t--) { scanf ("%d" , &x); G[i].push_back(x); } } solve(); printf ("%d\n" , sum); return 0 ; }
J. Prime Game
solved by Sstee1XD. 1:11(+)
题意 :给定序列a,定义
m u l ( l , r ) = ∏ i = l r a i mul(l, r) = \prod_{i = l}^ra_i m u l ( l , r ) = ∏ i = l r a i
f a c ( l , r ) fac(l, r) f a c ( l , r ) 为m u l ( l , r ) mul(l, r) m u l ( l , r ) 的不同质因子的数量
让你计算∑ i = 1 n ∑ j = i n f a c ( i , j ) \sum_{i = 1}^n\sum_{j = i}^nfac(i, j) ∑ i = 1 n ∑ j = i n f a c ( i , j ) 。
题解 :我们设 p r e v pre_v p r e v 为v v v 最后出现的位置。对于a i a_i a i 的质因子v v v ,它对于答案的贡献为对前面的贡献加上对后面的贡献,即 ( n − i + 1 ) ∗ ( i − p r e v − 1 ) + n − i + 1 (n - i +1)*(i-pre_v-1)+n-i+1 ( n − i + 1 ) ∗ ( i − p r e v − 1 ) + n − i + 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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 #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...);} inline int rd () { int s = 0 , w = 1 ; char ch = getchar(); while (ch < '0' || ch > '9' ){if (ch == '-' ) w = -1 ; ch = getchar();} while (ch >= '0' && ch <= '9' ) s = s * 10 + ch - '0' , ch = getchar(); return s * w; } typedef long long ll;const int inf = 0x3f3f3f3f ;const int maxn = 1e6 + 7 , N = 1e3 ;int prime[N + 10 ], cnt, flag[N + 10 ];void isprime () { for (int i = 2 ; i <= N; ++i) { if (!flag[i]) { prime[++cnt] = i; } for (int j = 1 ; j <= cnt; ++j) { if (1ll * prime[j] * i > N) break ; flag[prime[j] * i] = 1 ; if (i % prime[j] == 0 ) break ; } } } int n, pre[maxn], a[maxn];vector <int >G[maxn];void run () { for (int i = 1 ; i <= n; ++i) { a[i] = rd(); if (G[a[i]].size() == 0 && a[i] != 1 ) { int tmp = a[i]; for (int j = 1 ; j <= cnt; ++j) { if (tmp % prime[j] == 0 ) { G[a[i]].push_back(prime[j]); while (tmp % prime[j] == 0 ) { tmp /= prime[j]; } if (tmp == 1 ) break ; } } if (tmp > 1 ) G[a[i]].push_back(tmp); } } ll ans = 0 ; for (int i = 1 ; i <= n; ++i) { for (auto v : G[a[i]]) { ans += (ll)(n - i + 1 ) * (ll)(i - pre[v] - 1 ) + (ll)(n - i + 1 ); pre[v] = i; } } printf ("%lld\n" , ans); } int main () { isprime(); n = rd(); run(); return 0 ; }
K. Kangaroo Puzzle
solved by Sstee1XD. (-)
题意 :每次可以选择上下左右四个方向,一起移动所有的1 1 1 ,如果碰到0 0 0 或者墙就不动,最后要在50000 50000 5 0 0 0 0 步内使所有1 1 1 聚在一起。题目保证1不会转圈圈。
题解 :因为保证的存在,所以就直接随机输出50000 50000 5 0 0 0 0 个方向就好了(为什么会这么玄学?)。
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <bits/stdc++.h> using namespace std ;int main () { string s; int n, m; cin >> n >> m; while (n--) cin >> s; for (int i = 1 ; i <= 50000 ; ++i) { int x = rand()%4 ; if (x == 0 ) putchar ('U' ); if (x == 1 ) putchar ('D' ); if (x == 2 ) putchar ('R' ); if (x == 3 ) putchar ('L' ); } return 0 ; }
M. Mediocre String Problem
solved by Sstee1XD. (-)
题意 : 给你两个字符串s s s 和t t t ,对于t t t 中所有的前缀串k k k ,你要在s s s 中找到所有的子串s i j s_{ij} s i j ,使得s i j s_{ij} s i j 长度大于k k k ,并且将s i j s_{ij} s i j 与k k k 拼接后得到的字符串为回文串。问你最终的数量和。
题解 :为了让最后的字符串是回文串,对于前缀串k k k ,我们要先在s s s 中找到与前缀串k k k 一样的子串,再向后扩展,使得扩展的那部分字符串为回文串,即可实现。
我们先将t t t 进行反转,然后去遍历s s s ,那么现在的问题就转换成了找两个字符串的最长后缀(因为对于这部分所有的子串,他们的答案是一样的,所以最后求出来乘以最长后缀的长度就行了)。这里我们用哈希+二分来实现。
找出最长后缀后,我们假设当前遍历到s i s_i s i ,那么接下来我们要求以s i + 1 s_{i+1} s i + 1 为起点的回文串数量。想到回文串就想到了马拉车。马拉车可以求以每个点为中心的最长回文半径,那么对于以这个点为终点,以i i i - 最长回文半径的位置为起点,终点对于这段区间的贡献值为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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 #include <bits/stdc++.h> using namespace std ;typedef unsigned long long ull;typedef long long ll;const int maxn=1e6 + 7 ;const ull base = 131 ;char s[maxn], t[maxn];char ma[maxn<<1 ];ll mp[maxn<<1 ], paw[maxn]; ull gap[maxn], hashS[maxn], hashT[maxn]; void init () { gap[0 ] = 1 ; for (int i = 1 ; i <= 1000000 ; ++i) { gap[i] = gap[i - 1 ] * base; } } void makeHash (char *s, ull *hash) { int len = strlen (s); for (int i = 0 ; i < len; ++i) { hash[i + 1 ] = hash[i] * base + (ull)s[i]; } } ull getHash (int l, int r, ull *hash) { return hash[r + 1 ] - hash[l] * gap[r - l + 1 ]; } void manacher (char *s) { int len = strlen (s); int l=0 ; ma[l++]='$' ; ma[l++]='#' ; for (int i = 0 ;i < len; ++i){ ma[l++] = s[i]; ma[l++] = '#' ; } ma[l] = 0 ; ll mx = 0 , id = 0 ; for (int i = 0 ; i < l; ++i){ mp[i] = mx > i? min(mp[2 * id - i], mx - i) : 1 ; while (ma[i + mp[i]] == ma[i - mp[i]]) mp[i]++; if (i + mp[i] > mx){ mx = i + mp[i]; id = i; } } for (int i = 1 ; i < l; i++) { paw[(i >> 1 ) - (mp[i] >> 1 )]++; paw[(i >> 1 )]--; } for (int i = 1 ; i < len; ++i) { paw[i] += paw[i - 1 ]; } } void solve () { int len = strlen (s); int lent = strlen (t); int l, r, mid; ll ans = 0 ; ll maxx; for (int i = 0 ; i < len - 1 ; ++i) { l = 1 , r = i + 1 ; maxx = 0 ; while (l <= r) { mid = l + r >> 1 ; if (getHash(i - mid + 1 , i, hashS) == getHash(lent - mid, lent - 1 , hashT)) { maxx = mid; l = mid + 1 ; } else r = mid - 1 ; } ans += maxx * paw[i + 1 ]; } printf ("%lld\n" , ans); } int main () { init(); scanf ("%s %s" , s, t); reverse(t, t + strlen (t)); manacher(s); makeHash(s, hashS); makeHash(t, hashT); solve(); return 0 ; }