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

知-返發表於2024-07-31

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

相關文章