Educational Codeforces Round 168 (Rated for Div. 2) A - E

A. Strong Password

如果有两个相邻的字符相同,就在这两个字符就在中间插入一个不同的字符。

否则在第一个字符前面插入一个不同于第一个字符的字符

代码

点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;

const int N = 2e5 + 10,INF = 1e9,mod = 998244353;

int n,m,k;

void solve()
{
    string s;cin >> s;
    n = s.size();
    s = " " + s;
    char c = 'a';
    FOR(i,2,n)
    {
        if (s[i] == s[i - 1])
        {
            FOR(j,1,i - 1) cout << s[j];
            if (c == s[i]) c = 'b';
            cout << c;
            FOR(j,i,n) cout << s[j];
            cout << '\n';
            return;
        }
    }
    if (s[1] == c) c = 'b';
    cout << c;
    FOR(i,1,n) cout << s[i];
    cout << '\n';
}


signed main()
{
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T = 1;
    cin >> T;

    while(T --)
    {
        solve();
    }

    return 0;
}

B. Make Three Regions

由于最多只会有一个联通块,所以答案只有在一种情况下才会增加:
第一行下标为 \(1\) ,第二行下标为 \(2\) ,当前位第 \(i\) 行第 \(j\)

\(i\backslash j\) \(j-1\) \(j\) \(j+1\)
$ i $ . . .
\(3-i\) x . x

代码

点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;

const int N = 2e5 + 10,INF = 1e9,mod = 998244353;

int n,m,k;
char c[3][N];

void solve()
{
    cin >> n;
    FOR(i,1,2)
        FOR(j,1,n)
            cin >> c[i][j];
    int ans = 0;
    FOR(i,1,2)
        FOR(j,2,n - 1)
            if (c[i][j - 1] == '.' && c[i][j] == '.' && c[i][j + 1] == '.' &&
                c[3 - i][j - 1] == 'x' && c[3 - i][j] == '.' && c[3 - i][j + 1] == 'x')
                    ans ++;
    ANS;
}


signed main()
{
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T = 1;
    cin >> T;

    while(T --)
    {
        solve();
    }

    return 0;
}

C. Even Positions

维护当前 '(' 比 ')' 多的数量,如果当前位置是奇数位的话,那么如果能放 ')' 就放上去,否则放上 '('。

对于每一个 '(' 可以开一个队列记录从左往右的位置,如果遇到 ')' 的话,这个 ')' 肯定是和队头的那个 '(' 匹配的,所以 ')' 肯定是放在越左边越好的。

代码

点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;

const int N = 2e5 + 10,INF = 1e9,mod = 998244353;

int n,m,k;
char c[N];

void solve()
{
    cin >> n;
    FOR(i,1,n) cin >> c[i];
    queue<int> q;
    int now = 0,ans = 0;
    FOR(i,1,n)
    {
        if (c[i] == '(') now ++;
        else if (c[i] == ')') now --;
        else
        {
            if (now > 0) c[i] = ')',now --;
            else c[i] = '(',now ++;
        }
        if (c[i] == '(') q.push(i);
        else ans += i - q.front(),q.pop();
    }
    ANS;
}


signed main()
{
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T = 1;
    cin >> T;

    while(T --)
    {
        solve();
    }

    return 0;
}

D. Maximize the Root

\(dp[i]\) 表示 \(i\) 节点及其子树可以取到的最大的最小值

转移方程

如果 \(i\) 节点是叶子节点 \(~~\) : \(dp[i] = a[i]\)

如果 \(i\) 节点不是叶子节点 : 设 $ t = min(dp[j])~~~~~(\forall j\in G[i]) ~$

\[dp[i]= \begin{cases} (t + a[u]) / 2,\quad (a[u] \leq t)\\ ~~~~~~~t~~~~~~~~~~~, ~\quad (a[u] > t) \end{cases} \]

答案是 $ a[1] + min(dp[i])~~~~~(\forall i\in G[1]) ~$

代码

点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;

const int N = 2e5 + 10,INF = 1e9,mod = 998244353;

int n,m,k;
int dp[N],a[N];
vector<int> G[N];
int ans;

void dfs(int u)
{
    dp[u] = 1e18;
    for(auto i : G[u])
    {
        dfs(i);
        dp[u] = min(dp[u],dp[i]);
    }
    if (dp[u] == 1e18) dp[u] = a[u];
    else
    {
        if (u == 1) ans = dp[u] + a[u];
        else
        {
            if (dp[u] >= a[u]) dp[u] = (dp[u] + a[u]) / 2;
        }
    }
}

void solve()
{
    cin >> n;
    FOR(i,1,n) G[i].clear();
    FOR(i,1,n) cin >> a[i];
    FOR(i,2,n)
    {
        int fa;cin >> fa;
        G[fa].emplace_back(i);
    }
    ans = 0;
    dfs(1);
    ANS;
}


signed main()
{
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T = 1;
    cin >> T;

    while(T --)
    {
        solve();
    }

    return 0;
}

E. Level Up

先将所有的询问记录下来,然后枚举每个 \(k\) ,对于每个 \(k\) \(Monocarp\) 最多会提升 \(n / k\) 次等级,一共会提升 \(\sum_{k=1}^n n/k\approx n * log_2n\) 次等级,在提升等级的同时算出每一个询问的答案。

接下来需要考虑如何找到每个 \(k\) 的每个等级提升时的边界,假设当前左端点为 $ l$ 等级为 \(level\) ,可以用二分在 $l $ 到 $ n$ 之间找到最靠左的端点 \(r\) 使得 \(\sum_{i = l}^{r}(a[i] \geq level ) \geq k\) , 可以从 \(1\)\(n\) 枚举 \(level\) ,然后更新每一个 \(k\) 的左端点,可以用 \(RMQ\) 来维护区间内大于等于当前 \(level\)\(a[i]\) 的个数。

这里用的是树状数组,每次更新一个 \(level\) 的时候将权值为 \(level\) 的所以 \(a[i]\) 加入树状数组,这样就可以保证在树状数组中加入的点都是严格小于当前 \(level\) 的。

代码

点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;

const int N = 2e5 + 10,INF = 1e9,mod = 998244353;

int n,m,k,Q;
int ans[N];
int yuan[N];
vector<int> alls[N];

struct treearray
{
    vector<int> tre;int kk;
    treearray(){}
    treearray(int n){init(n);}
    void init(int n){tre.resize(n);kk = n;}
    int lowbit(int x){return x&(-x);}
    int ask(int i){int ans=0; for(;i;i-=lowbit(i))ans+=tre[i];return ans;}
    void add(int i,int d){for(;i<=kk;i+=lowbit(i))tre[i]+=d;}
};

void solve() {
    cin >> n >> Q;
    vector<int> a[N];
    FOR(i, 1, n) 
    {
        int x;cin >> x;
        yuan[i] = x;
        a[x].emplace_back(i);
    }
    priority_queue<PII, vector<PII >, greater<>> q[N];
    FOR(t, 1, Q) 
    {
        int i, x;cin >> i >> x;
        q[x].push({i, t});
    }//pos, id

    treearray tr(2e5 + 1);

    vector<PII> now[N];//pos,k
    FOR(i, 1, n) now[1].emplace_back(1, i);

    FOR(i, 1, n) 
    {
        for (auto [pos, k]: now[i]) 
        {
            int l = pos, r = n;
            while (l < r) 
            {
                int mid = l + r >> 1;
                if (mid - pos + 1 - (tr.ask(mid) - tr.ask(pos - 1)) >= k) r = mid;
                else l = mid + 1;
            }
            int newpos = l;

            while (q[k].size() && q[k].top().first <= newpos) 
            {
                auto [qpos, id] = q[k].top();
                q[k].pop();
                if (yuan[qpos] >= i) ans[id] = 1;
                else ans[id] = 0;
            }
            newpos ++;
            if (newpos <= n)
            {
                now[i + 1].emplace_back(newpos,k);
            }
        }
        //算 >= i的个数
        for (auto j: a[i]) tr.add(j, 1);
    }

    FOR(i, 1, Q)
    {
        if (ans[i]) YES;
        else NO;
    }
}


signed main()
{
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T = 1;
//    cin >> T;

    while(T --)
    {
        solve();
    }

    return 0;
}
posted @ 2024-07-31 02:45  知-返  阅读(86)  评论(1编辑  收藏  举报