比赛链接 / 官方题解链接
A. Arena 显然只有最小的数没法增大,而其他数都能无限增大。
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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;typedef vector<int > vi;typedef pair<int , int > pii;#define mp(x, y) make_pair(x, y) #define pb(x) emplace_back(x) const int N = 105 ;int n, a[N];int main () { int T; for (read (T); T; T--){ read (n); for (int i = 1 ; i <= n; i++) read (a[i]); sort (a+1 , a+n+1 ); int cnt = 0 ; for (int i = 1 ; i <= n; i++){ if (a[i] == a[1 ]) cnt++; else break ; } printf ("%d\n" , n - cnt); } return 0 ; }
B. Cat Cycle 如果 $n$ 是偶数,那么 $A,B$ 永远不会冲突,答案很好计算。
否则,自上一次冲突后,$A,B$ 的下一次冲突将发生在 $\frac{n-1}{2}$ 步后,也就是说,$B$ 会先以步长为 $1$ 走 $\frac{n-3}{2}$ 次,然后以步长为 $2$ 走 $1$ 次,以此循环。答案乱搞搞就算出来了。
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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;typedef vector<int > vi;typedef pair<int , int > pii;#define mp(x, y) make_pair(x, y) #define pb(x) emplace_back(x) LL n, k; int main () { int T; for (read (T); T; T--){ read (n, k); if (n % 2 == 0 ){ printf ("%lld\n" , (k - 1 ) % n + 1 ); continue ; } if (k * 2 <= n - 1 ){ printf ("%lld\n" , k); continue ; } if (k * 2 == n + 1 ){ printf ("%lld\n" , k + 1 ); continue ; } k -= (n + 1 ) / 2 ; LL t = (n - 3 ) / 2 ; LL st = (n + 1 ) / 2 + 1 ; st += k / (t + 1 ) * (t + 2 ); st += k % (t + 1 ); st = (st - 1 ) % n + 1 ; printf ("%lld\n" , st); } return 0 ; }
C. Minimum Ties 以步长 $1$ 转着圈赢:$1\to2,\,2\to3,\,3\to4,\ldots$;
然后以步长为 $2$ 转着圈赢:$1\to3,\,2\to4,\,3\to5,\ldots$;
然后以步长为 $3$ 转着圈赢:$1\to4,\,2\to5,\ldots$;
如果 $n$ 是奇数,这样就保证了每个点出度和入度相等;如果 $n$ 是偶数,多的出度/少的入度变成平局即可。
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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;typedef vector<int > vi;typedef pair<int , int > pii;#define mp(x, y) make_pair(x, y) #define pb(x) emplace_back(x) int main () { int T; for (read (T); T; T--){ int n; read (n); if (n & 1 ){ for (int l = n - 1 ; l >= 1 ; l--) for (int i = 1 ; i <= l; i++) printf ("%d " , i <= n / 2 ? 1 : -1 ); puts ("" ); } else { for (int l = n - 1 ; l >= 1 ; l--) for (int i = 1 ; i <= l; i++) printf ("%d " , i == n / 2 ? 0 : (i < n / 2 ? 1 : -1 )); puts ("" ); } } return 0 ; }
D. Pythagorean Triples 为满足 $1\leqslant a\leqslant b\leqslant c\leqslant n$,首先需要:$n\geqslant 5$,其次 $a=2k+1$ 是奇数,再次:$c=2k^2+2k+1\leqslant n$. 可以直接解方程,不过为了避免奇怪的精度问题,我这里采用二分。
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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;typedef vector<int > vi;typedef pair<int , int > pii;#define mp(x, y) make_pair(x, y) #define pb(x) emplace_back(x) int main () { int T; for (read (T); T; T--){ LL n; read (n); if (n < 5 ){ printf ("%d\n" , 0 ); continue ; } LL l = 1 , r = n; while (l < r){ LL mid = (l + r + 1 ) >> 1 ; if (2 * mid * mid + 2 * mid + 1 <= n) l = mid; else r = mid - 1 ; } printf ("%lld\n" , l); } return 0 ; }
E. Cheap Dinner 按当前代价顺序考虑当前层的点,向下一层可以转移到的点转移即可。使用堆进行处理,由于每个点最多转移一次,每个限制条件最多被遍历一次,所以转移个数是 $O(n+m)$ 的。
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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;typedef vector<int > vi;typedef pair<int , int > pii;#define mp(x, y) make_pair(x, y) #define pb(x) emplace_back(x) const int N = 150005 ;int n1, n2, n3, n4, a[N], b[N], c[N], d[N], m[5 ];set<int > edge[5 ][N]; set<int > s1, s2, s3, s4; int main () { read (n1, n2, n3, n4); for (int i = 1 ; i <= n1; i++) read (a[i]), s1.insert (i); for (int i = 1 ; i <= n2; i++) read (b[i]), s2.insert (i); for (int i = 1 ; i <= n3; i++) read (c[i]), s3.insert (i); for (int i = 1 ; i <= n4; i++) read (d[i]), s4.insert (i); for (int i = 1 ; i <= 3 ; i++){ read (m[i]); for (int j = 1 ; j <= m[i]; j++){ int u, v; read (u, v); edge[i][u].insert (v); } } priority_queue< pii, vector<pii>, greater<pii> > q, tmp1, tmp2, tmp3; for (int i = 1 ; i <= n1; i++) q.push (mp (a[i], i)); while (!q.empty ()){ pii cur = q.top (); q.pop (); vi ers; for (auto &elem : s2){ if (edge[1 ][cur.second].find (elem) == edge[1 ][cur.second].end ()){ tmp1.push (mp (cur.first + b[elem], elem)); ers.pb (elem); } } for (auto &e : ers) s2.erase (e); if (s2.empty ()) break ; } q = tmp1; while (!q.empty ()){ pii cur = q.top (); q.pop (); vi ers; for (auto &elem : s3){ if (edge[2 ][cur.second].find (elem) == edge[2 ][cur.second].end ()){ tmp2.push (mp (cur.first + c[elem], elem)); ers.pb (elem); } } for (auto &e : ers) s3.erase (e); if (s3.empty ()) break ; } q = tmp2; while (!q.empty ()){ pii cur = q.top (); q.pop (); vi ers; for (auto &elem : s4){ if (edge[3 ][cur.second].find (elem) == edge[3 ][cur.second].end ()){ tmp3.push (mp (cur.first + d[elem], elem)); ers.pb (elem); } } for (auto &e : ers) s4.erase (e); if (s4.empty ()) break ; } q = tmp3; if (q.empty ()) puts ("-1" ); else printf ("%d\n" , q.top ().first); return 0 ; }