Educational Codeforces Round 17

Educational Codeforces Round 17

https://codeforces.com/contest/762

A. k-th divisor

#include <bits/stdc++.h>
#define ll long long

using namespace std;
ll n, k;

void get_div (ll x) {
    vector<ll> v;
    v.push_back (1);
    if (x != 1)     v.push_back (x);
    for (ll i = 2; i*i <= x; i++) {
        if (x % i == 0) {
            v.push_back (i);
            if (i !=  x / i) {
                v.push_back (x / i);
            }
        }
    }
    sort (v.begin (), v.end ());
    //cout << v.size () << endl;
    //for (auto i : v)    cout << i << ' ';  cout << endl;
    if (v.size () < k)      cout << -1;
    else    cout << v[k-1];
}

int main () {
    cin >> n >> k;
    get_div (n);
}

B. USB vs. PS/2

#include <bits/stdc++.h>
#define ll long long

using namespace std;
int a, b, c, n, cnt;
ll ans;
multiset<int> s1, s2;

int main () {
    cin >> a >> b >> c >> n;
    for (int i = 0; i < n; i++) {
        int x;
        string s;
        cin >> x >> s;
        if (s[0] == 'U')    s1.insert (x);
        else    s2.insert (x);
    }

    while (s1.size () && a > 0) {
        cnt ++, ans += *s1.begin ();
        s1.erase (s1.begin ()), a --;
    }
    while (s2.size () && b > 0) {
        cnt ++, ans += *s2.begin ();
        s2.erase (s2.begin ()), b --;
    }
    multiset<int> s;
    for (auto i : s1)   s.insert (i);
    for (auto i : s2)   s.insert (i);
    while (s.size () && c > 0) {
        cnt ++, c --;
        ans += *s.begin ();
        s.erase (s.begin ());
    }
    cout << cnt << ' ' << ans << endl;
}

C. Two strings

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int posl[N], posr[N], ansr, ansl, n, m;

bool check (int l, int r) { //删掉[l,r]
    if (posl[l-1] < posr[r+1])    return true;
    return false;
}

int main () {
    string a, b;
    cin >> a >> b;
    n = a.size (), m = b.size ();
    a = ' ' + a, b = ' ' + b;
    ansl = 0, ansr = m + 1;
    for (int i = 0; i <= m + 1; i++)    posl[i] = n + 1;
    
    //预处理匹配
    for (int i = 1, j = 1; i <= m && j <= n; j++) {
        if (a[j] == b[i])   posl[i] = j, i ++;
    }
    for (int i = m, j = n; i >= 1 && j >= 1; j--) {
        if (a[j] == b[i])   posr[i] = j, i --;
    }

    //for (int i = 1; i <= m; i++)    cout << posl[i] << ' '; cout << endl;
    //for (int i = 1; i <= m; i++)    cout << posr[i] << ' '; cout << endl;

    if (posl[1] == n + 1 && posr[m] == 0) {
        cout << '-';
        return 0;
    }

    //if (posl[1] == n + 1) { //删前缀
        for (int i = 1; i <= m; i++) {
            if (posr[i] != 0) {
                ansl = 1, ansr = i - 1;
                break;
            }
        }
    //}
    //else if (posr[m] == 0) { //删后缀
        for (int i = m; i >= 1; i--) {
            if (posl[i] != n + 1) {
                if (m - i - 1 < ansr - ansl)    ansl = i + 1, ansr = m;
                break;
            }
        }
    //}
    //else {
        //二分枚举
        for (int l = 1; l <= m; l++) {
            int tl = l, tr = m;
            while (tl < tr) {
                int mid = tl + tr >> 1;
                if (check (l, mid))    tr = mid;
                else    tl = mid + 1;
                //cout << l << ' ' << tr << endl;
            }
            //cout << endl;
            if (check (l, tr)) {
                int r = tr;
                if (ansr - ansl > r - l)    ansl = l, ansr = r;
            }
        }
    //}

    if (!ansl)    cout << '-';
    else {
        //cout << ansl << ' ' << ansr << endl;
        for (int i = 1; i < ansl; i++)  cout << b[i];
        for (int i = ansr + 1; i <= m; i++) cout << b[i];
    }
}

//题意: 把b删掉一段连续的后,使其成为a的子序列,输出删去后满足条件的最长b
//优化枚举: 找到合法方案后, 删除更多依旧合法, 故枚举左端点, 二分右端点
//优化匹配: (核心: 每个b都有在a中对应的位置, 因为a不变所以可以记录位置)
//posl[i]: b中[1,i]的字符匹配到a里, 第i个元素在a中对应的位置(前缀匹配)
//posr[i]: b中[i,lenb]的字符匹配到a里, 第i个元素在a中对应的位置(后缀匹配)
//则匹配等价于check是否满足posl[l-1] < posr[r+1]即可

D. Maximum path

嗨难想的状态

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 1e5 + 5, inf = -1e18;
int ans = -1e18;
int f[N][5]; //对应第i列的5种情况
int a[5][N], n, m;
int s1, s2, s3, s12, s23, s123;

signed main () {
    cin >> m;
    n = 3;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
            for (int k = 0; k < 5; k++)     f[j][k] = inf;
        }
    }
    s1 = a[1][1], s12 = a[1][1] + a[2][1], s123 = s12 + a[3][1];
    f[1][0] = s1, f[1][1] = s12, f[1][2] = f[1][3] = s123; 
    for (int i = 2; i <= m; i++) {
        int st0 = f[i-1][0], st1 = f[i-1][1], st2 = f[i-1][2], st3 = f[i-1][3], st4 = f[i-1][4];
        s1 = a[1][i], s2 = a[2][i], s3 = a[3][i], s12 = s1 + s2, s23 = s2 + s3, s123 = s1 + s23;
        f[i][0] = max ({st0 + s1, st1 + s12, st2 + s123, st4 + s123});
        f[i][1] = max ({st0 + s12, st1 + s2, st2 + s23});
        f[i][2] = max ({st0 + s123, st1 + s23, st2 + s3, st3 + s123});
        f[i][3] = st0 + s123;
        f[i][4] = st2 + s123;
    }
    cout << max (f[m][2], f[m][3]) << endl;
}

//偶数的时候可以被不返回的路径代替
//奇数的时候往左可以转化为,每次只往回走一格,可以枚举返回的位置,转化为子问题
//设五个状态

E. Radio stations

F. Tree nesting

posted @ 2023-01-16 00:10  Sakana~  阅读(27)  评论(0编辑  收藏  举报