Educational Codeforces Round 104

发布时间 2023-08-02 17:43:10作者: PHarr

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;
}