Codeforces Round #828 (Div. 3)

Codeforces Round #828 (Div. 3)

https://codeforces.com/contest/1744
罚时爆炸的a~e1

A. Number Replacement

数字一样的对应字母一定要一样。
我写的好复杂,不知道为啥脑抽了,写了巨久

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
const int N = 55;

void solve () {
    int n;
    cin >> n;
    vector <int> v[N];
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        v[x].push_back (i);
    }
    
    string s;
    cin >> s;
    for (int i = 1; i <= 50; i++) {
        if (v[i].empty ())  continue;
        for (int j = 1; j < v[i].size (); j++) {
            if (s[v[i][j]] != s[v[i][j-1]]) {
                puts ("NO");
                return ;
            }
        }
    }
    puts ("YES");
}

int main () {
    int t;
    cin >> t;
    while (t --)    solve ();
}

B. Even-Odd Increments

奇偶数加减性质,详见代码注释

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

using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 5;
int a[N];

void solve () {
    int n, q, ans = 0, odd = 0, even = 0;
    cin >> n >> q;
    for (int i = 1; i <= n; i++) {
        cin >> a[i], ans += a[i];
        if (a[i] & 1)   odd ++;
        else    even ++;
    }
    
    while (q --) {
        int op, x;
        cin >> op >> x;
        if (op == 0) {
            //偶+x
            if (x & 1) {
                //偶 + 奇数 = 奇
                ans += even * x;
                //全变奇
                odd = n, even = 0;
            }
            else {
                //偶 + 偶 = 偶
                ans += even * x;
            }
        }
        else {
            if (x & 1) {
                //奇 + 奇 = 偶
                ans += odd * x;
                //全变偶
                even = n, odd = 0;
            }
            else {
                // 奇 + 偶 = 奇
                ans += odd * x;
            }
        }
        cout << ans << endl;
    }
}

signed main () {
    int t;
    cin >> t;
    while (t --)    solve ();
}

C. Traffic Light

二分到离他最近的green
脑抽,T了两发

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;
int a[N];

void solve () {
    int n;
    char c;
    string s;
    cin >> n >> c >> s;
    if (c == 'g') {
        cout << "0\n";
        return ;
    }
    set <int> ss;
    for (int i = 0; i < n; i++) {
        if (s[i] == 'g')    ss.insert (i);
    }

    //s += s;
    int ans = 0, tt = *ss.begin ();
    for (int i = 0; i < n; i++) {
        if (s[i] == c) {
            auto it = ss.upper_bound (i);
            if (it == ss.end ())    ans = max (ans, n - i + tt);
            else    ans = max (ans, *it - i);
        }
    }
    cout << ans << "\n";
}

signed main () {
    ios::sync_with_stdio (0);cin.tie (0);cout.tie (0);
    int t;
    cin >> t;
    while (t --)    solve ();
}

D. Divisibility by 2^n

首先分解每个数,看能拼出多少个2,统计因子2的个数为cnt,如果cnt>=n,则不需要额外操作
否则对于2,4,6,8,...偶数位上的数*i能增加对应的2因子数,即对n以内的偶数(2,4,6,...,n或n-1)再进行2的因数分解,按照所含2因数的个数降序排序,然后挨个加,直至cnt>=n即可

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

using namespace std;
const int N = 2e5 + 5;

void solve () {
    int n, cnt = 0; //2的个数, 额外的
    cin >> n;
    vector <int> v;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        while (x % 2 == 0)  x /= 2, cnt ++;
        int dx = 0, j = i;
        while (j % 2 == 0)  j /= 2, dx ++;
        if (dx) v.push_back (dx);
    }
    if (cnt >= n) {
        cout << "0\n";
        return ;
    }
    int res = n - cnt;
    sort (v.begin (), v.end (), greater <int> ());
    
    int pos = 0, ans = 0;
    while (res > 0 && pos < v.size ()) {
        res -= v[pos ++];
        ans ++;
    }

    if (res > 0)    cout << "-1\n";
    else    cout << ans << "\n";
}

signed main () {
    ios::sync_with_stdio (0);cin.tie (0);cout.tie (0);
    int t;
    cin >> t;
    while (t --)    solve ();
}

//看缺几个2,补就完了

E1. Divisible Numbers (easy version)

枚举x,利用gcd的性质来check y的合法性

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

using namespace std;

void solve () {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    int m = a * b;
    if (c - a <= b - d) {
        for (int i = a + 1; i <= c; i++) {
            int ans = m / __gcd (m, i);
            //cout << "ans=" << ans << endl;
            if (ans > d)    continue;
            int base = ans;
            for (int j = 1; ans <= d; j++) {
                ans = base * j;
                //cout << "ans=" << ans << endl;
                if (ans > b)    break;
            }
            if (ans <= d) {
                cout << i << ' ' << ans << "\n";
                return ;
            }
        }
        cout << "-1 -1\n";
    }
    else {
        for (int i = b + 1; i <= d; i++) {
            int ans = m / __gcd (m, i);
            //cout << "ans=" << ans << endl;
            if (ans > c)    continue;
            int base = ans;
            for (int j = 1; ans <= c; j++) {
                ans = base * j;
                //cout << "ans=" << ans << endl;
                if (ans > a)    break;
            }
            if (ans <= c) {
                cout << ans << ' ' << i << "\n";
                return ;
            }
        }
        cout << "-1 -1\n";
    }
}

signed main () {
    ios::sync_with_stdio (0);cin.tie (0);cout.tie (0);
    int t;
    cin >> t;
    while (t --)    solve ();
}

//交叉构造

E2. Divisible Numbers (hard version)

因数分解,赛时不知道怎么处理因数的组合。
其实可以用背包思想,map来更新它的合法性
详见代码

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

using namespace std;

void get_div (int x, vector <int> &v) {
    for (int i = 2; i * i <= x; i++) {
        while (x % i == 0) {
            v.push_back (i);
            x /= i;
        }
    }
    if (x > 1)  v.push_back (x);
}

void solve () {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    int m = a * b;
    
    vector <int> v;
    get_div (a, v), get_div (b, v);
    map <int, bool> dp; //储存c范围内的素因子组合
    dp[1] = true;

    for (auto i : v) { //枚举a*b的所有因子
        auto tmp = dp;
        for (auto j : dp) {
            if (i * j.first <= c)   tmp[i * j.first] = true;
        }
        dp = tmp;
    }

    //for (auto i : dp)   cout << i.first << ' ';cout << endl;

    for (auto i : dp) {
        int x = i.first;
        int y = m / x;
        x = x * (c / x), y = y * (d / y); //限定范围下的上界
        if (x > a && y > b) {
            if (x <= c && y <= d && (x * y) % (a * b) == 0) {
                cout << x << ' ' << y << "\n";
                return ;
            }
        }
    }

    cout << "-1 -1\n";
}

signed main () {
    ios::sync_with_stdio (0);cin.tie (0);cout.tie (0);
    int t;
    cin >> t;
    while (t --)    solve ();
}

//质因数分解

F. MEX vs MED

重要性质:要满足 mex > med,必须有区间长度 <= 2 * mex
简单说明:mex = i 时,代表了区间l,r出现了0~i-1的数,那么这些数总共就占了i的长度,要使得中位数med < mex,区间长度就不能超过 2*i,否则med 就会>= i了
以这一点为标准,就可以确定区间长度的上界了,然后下界就是最开始枚举出的l,r (必须包含0~i-1且无i)即最小区间。
由最小区间延伸的标准是:往 i 所在的方向延伸。

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5;
int a[N], pos[N], n;

void solve () {
    cin >> n;
    for (int i = 0; i <= n; i++)    pos[i] = 0;
    for (int i = 1; i <= n; i++)    cin >> a[i], pos[a[i]] = i;
    long long ans = 0;
    int l = pos[0], r = pos[0];
    for (int i = 1; i <= n; i++) {
        if (l <= pos[i] && pos[i] <= r)     continue; //不满足mex
        int len = r - l + 1;
        if (len <= 2 * i) { //满足med
            if (r < pos[i]) { //i在右
                for (int j = r; j < pos[i]; j++) {
                    int dx = max (1, j - (2 * i - 1));
                    ans += max (0, l - dx + 1);
                }
            }
            else {
                for (int j = pos[i] + 1; j <= l; j++) {
                    int dx = min (n, j + (2 * i - 1));
                    ans += max (0, dx - r + 1);
                }
            }
        }
        l = min (l, pos[i]), r = max (r, pos[i]);
    }
    cout << ans << endl;
}

int main () {
    int t;
    cin >> t;
    while (t --)    solve ();
}
posted @ 2022-10-17 21:50  Sakana~  阅读(182)  评论(0编辑  收藏  举报