Educational Codeforces Round 104
https://codeforces.com/contest/1487
A. Arena
统计与最小值不同的数字数量。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M = (1 << 15) - 1;
void solve(){
int n;
cin >> n;
vector<int> a(n);
for( auto &i : a )
cin >> i;
sort(a.begin(), a.end());
for( auto i : a ){
if( i != a[0] ) break;
n --;
}
cout << n << "\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while( t -- )
solve();
return 0;
}
B. Cat Cycle
首先如果\(n\)是偶数,则\(A,B\)不会相遇。当\(n\)是奇数是,\(B\)每一圈都多走了 1 步,这里的一圈是指圈上所有的点被覆盖过一次,并且每\(\frac{n}{2}\)步可以完整的覆盖一次。所以计算完整覆盖了多少次即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M = (1 << 15) - 1;
void solve() {
int n, k, f;
cin >> n >> k, k -- , f = n / 2;
cout << (k + (n % 2) * (k / f)) % n + 1 << "\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
C. Minimum Ties
首先,当\(n\)为奇数的时候,每只球队需要参与偶数场比赛,所以不用平局,反之每只球队至少产生一次平局。
我们保证球队\(i\)赢\(j\)在\(2(j-i)<n\)即可。
当然本题构造方法有很多种。
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin >> n;
for( int i = 1 ; i <= n ; i ++ )
for( int j = i+1 ; j <= n ; j ++ ){
if( 2*(j-i) == n ) cout << "0 ";
else if( 2*(j-i) < n ) cout <<"1 ";
else cout << "-1 ";
}
cout << "\n";
return ;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while( t -- )
solve();
return 0;
}
D. Pythagorean Triples
我们要找同时满足\(1\le a\le b \le c \le n , a^2+b^2=c^2,a^2-b=c\)
的\((a,b,c)\)的数量,首先把两个等式作差可以得到\(b^2+b=c^2-c\)则\(b(b+1)=c(c-1)\),所以\(c=b+1\)
带回原式可得\(a^2=2b+1\)因为\(b\le n\)所以\(a^2=2b+1\le 2n+1\)。这样我们\(O(\sqrt n)\)的求出所有符合条件的\(a\)即可,当然也可以用数学方法\(O(1)\)的解出答案。
另外一点要注意的是\(a^2=2b+1\),所以\(a\)一定是奇数。
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n , res = 0;
cin >> n;
for( int i = 3 , N = 2*n-1; i * i <= N ; i += 2 )
res ++;
cout << res << "\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while( t -- )
solve();
return 0;
}
E. Cheap Dinner
设\(f[i][j]\)表示第\(i\)种菜,选择\(j\)的最小代价,则转移方程就是\(f[i][j]=\min f[i-1][k] + a[i][j],(k,j)\notin\{(x_{i-1},y_{i-1})\}\),这样的话实际上转换成了一个带修改的 RMQ问题,并且每次询问的区间都是完整的区间,当然我们可以使用各种数据结构来解决这个问题。
这里我们 multiset 来维护\(f[i-1][k]\)的最小值,每次枚举点后,把所有不能转移过来的点删掉,计算答案后再重新加回去,复杂度\(O(m\log n)\)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 1e18;
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
vector<int> n(4);
for (auto &i: n) cin >> i;
vector<vector<int>> a(4);
for (int i = 0; i < 4; i++) {
a[i] = vector<int>(n[i]);
for (auto &j: a[i]) cin >> j;
}
for (int i = 1, m; i < 4; i++) {
cin >> m;
vector<vector<int>> e(n[i] + 1);
for (int x, y; m; m--)
cin >> x >> y, x--, y--, e[y].push_back(x);
multiset<int> cnt;
for (auto j: a[i - 1])
cnt.insert(j);
for (int j = 0; j < n[i]; j++) {
for (auto k: e[j])
cnt.erase(cnt.lower_bound(a[i - 1][k]));
if (cnt.empty()) a[i][j] = inf;
else a[i][j] += *cnt.begin();
for (auto k: e[j])
cnt.insert(a[i - 1][k]);
}
}
int res = *min_element(a[3].begin(), a[3].end());
if( res >= inf ) res = -1;
cout << res;
return 0;
}