Educational Codeforces Round 132 (Rated for Div. 2) A-D

Educational Codeforces Round 132 (Rated for Div. 2)

https://codeforces.com/contest/1709
这场ab很模拟(但我写的很慢),c居然比d难(策略性失误,悲)

A. Three Doors

读题读了半天

题意

有三扇门,编号1-3,只有对应的钥匙才能开这扇门。
初始的时候手里有一把钥匙
现在有两扇门后面各藏着一把钥匙,打开这扇门之后就能拿到这个钥匙。
问现有的条件下能否打开所有的门

分析

先拿手中的钥匙去开对应的门,开了之后门后钥匙对应的门也能被打开,对应的一一标记即可
(我写的比较繁琐。。。)

Code

#include <bits/stdc++.h>

using namespace std;
bool vis[4];

void solve () {
    memset (vis, false, sizeof vis);
    int x, a, b, c;
    cin >> x >> a >> b >> c;
    
    if (x == 1) {
        vis[1] = true;
        vis[a] = true;
        if (a == 3) vis[c] = true;
        else if (a == 2) vis[b] = true; 
    }
    else if (x == 2) {
        vis[2] = true;
        vis[b] = true;
        if (b == 3) vis[c] = true;
        else if (b == 1) vis[a] = true; 
    }
    else {
        vis[3] = true;
        vis[c] = true;
        if (c == 1) vis[a] = true;
        else if (c == 2)    vis[b] = true;
    }
    
    if (vis[3] && vis[1] && vis[2])   cout << "YES\n";
    else    cout << "NO\n";
}

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

B. Also Try Minecraft

题意

给定序列a,长度为n, 从 \(a_i\)\(a_j\) 有一个伤害值:如果 \(a_i < a_j\),则值为0;否则为 \(a_i-a_j\)。每次只能向相邻的转移,即只能从 \(a_i\)\(a_{i+1}\),或到 \(a_{i-1}\),(\(1<i<n\))。有q次询问,问每次从 \(s_j\)\(t_j\) 的最小伤害值是多少

分析

要么向前走要么向后走一格,然后伤害值又是非负数,那么走出去再倒回来的伤害值一定比直接走过去要大,所以没有策略而言,直接统计差值的前缀和即可。
正着一遍,倒着一遍

记得开long long !!!

Code

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

using namespace std;
const int N = 1e5 + 5;
int a[N], b[N], c[N], n;

void test () {
    for (int i = 1; i <= n; i ++)   cout << b[i] << ' ';
    cout << endl;
    for (int i = 1; i <= n; i ++)   cout << c[i] << ' ';
    cout << endl << endl;
}

void solve () {
    int m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++)   cin >> a[i];
    for (int i = 2; i <= n; i ++)   b[i] = max (0ll, a[i-1] - a[i]);
    for (int i = n-1; i >= 1; i --)   c[i] = max(a[i+1] - a[i], 0ll);

    //test();

    for (int i = 2; i <= n; i ++)   b[i] += b[i-1];
    for (int i = n-1; i >= 1; i --) c[i] += c[i+1];

    //test();

    while (m --) {
        int s, t;
        cin >> s >> t;
        if (s < t)  cout << b[t] - b[s] << endl;
        else    cout << c[t] - c[s] << endl;
    }
}

signed main () {
    solve ();
}
//s到t,每次可以前进或后退一格
//i->j:
//a[i]<a[j]:0
//a[i]>a[j]:a[i]-a[j]
//max(a[i]-a[j], 0)
//最小值
//答案是固定的,不会回退
//预处理

C. Recover an RBS

WA了5发并且是赛后过的(悲

题意

给一个字符串,包含 '(' ')' '?'
\(RBS\) 就是能够两两匹配的括号序列,'?'出表示还未确定。
问能否构造出 唯一 的括号序列
(题目保证一定存在一个括号序列)

分析

(n为字符串长度)

把 '(' 视为0, ')' 视为1,那么要形成 RBS 的条件就是:

\(1-n\) 任意前缀满足 \(cnt0\geq cnt1\),且最终

\(cnt1=cnt0=\frac n2\)

明确了这一点,就可以来构造序列了,必定存在的一种合法构造方式,就是尽可能把 '(' 放在前面,即在 \(cnt0<\frac n2\)的前提下都放'('。这样就必定构造出一种合法的 RBS 了。

然后在前面构造的过程中,记录?变为'('的位置,保存在v1, 记录?变为')'的位置,保存在v2。

然后枚举每一个'('和')',交换他俩的位置,交换之后check一下是否合法, 如果能找到一个合法的并且与最开始构造的 不一样的串,那么就表示不唯一。
否则,所有的都交换完了但还找到不一样的,就表示只有唯一的RBS

Code

#include <bits/stdc++.h>

using namespace std;

//是否合法
bool check (string s) {
    int n = s.size ();
    int cnt0 = 0, cnt1 = 0;
    for (int i = 0; i < n; i ++) {
        if (s[i] == '(')    cnt0 ++;
        else   cnt1 ++;
        if (cnt1 > cnt0)    return false;
    }
    if (cnt1 != cnt0)   return false;
    return true;
}

void solve () {
    string s;
    cin >> s;
    int n = s.size (), cnt = 0;
    int cnt1 = 0, cnt0 = 0;
    vector <int> v; //记录?的位置

    for (int i = 0; i < n; i ++) {
        if (s[i] == '?') {
            if (i == 0) s[0] = '(', cnt0 ++;
            else if (i == n-1)  s[n-1] = ')', cnt1 ++;
            else    cnt ++;
        } 
        else if (s[i] == '(')   cnt0 ++;
        else if (s[i] == ')')   cnt1 ++;
    }      

    if (cnt < 2 || cnt0 == n/2 || cnt1 == n/2) {
        cout << "YES\n";
        return ;
    }
    
    string t1 = s;    
    int st = n, ed = 0, res = n/2 - cnt0; //res表示最多还能放多少个'('
    cnt1 = cnt0 = 0;
    //cout << res << endl;

    vector <int> v1, v2;
    for (int i = 0; i < n; i ++) {
        if (s[i] == '(')    cnt0 ++;
        else if (s[i] == ')')   cnt1 ++;
        else {
            if (cnt0 == cnt1) {
                cnt0 ++, t1[i] = '(';
                v1.push_back (i), res --;//必为'('
            }   
            else {
                if (res)   {
                    cnt0 ++, t1[i] = '(';
                    v1.push_back (i), res --;//必为'('
                }   
                else    {
                    cnt1 ++, t1[i] = ')';
                    v2.push_back (i);//必为'('
                }    
            }
        }
    }
    //cout << t1 << endl;

    for (auto i: v1)
        for (auto j: v2) {
            string tmp = t1;
            swap (tmp[i], tmp[j]);
            if (check (tmp) && t1 != tmp) {
                cout << "NO\n";
                return ;
            }
        }
    cout << "YES\n";
}

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

//求 可匹配的括号序列是否唯一
//保证一定有合法序列
//n一定为偶数

//首尾固定
//'(': cnt0++;
//')': cnt1++;
//cnt0>=cnt1,且最终cnt1==cnt0

D. Rorororobot

题意

\(n*m\) 的方格,某些位置(\(1-a_m\))被block了
可以上下左右走但是只能一次走k个,且不能出界

q次询问,给定\((sx,sy),(fx,fy),k\), 问能不能从 s 走到 f 呢

统计曼哈顿距离

读入量大,不要用cin!!!!

分析

先判断横坐标之差和纵坐标之差是否都是k的倍数,不是一定走不到
对于每一列,最远能够走到:

\[maxn=x+\lfloor\frac {n-x}k\rfloor \times k \]

故只需查询区间 \([l,r]\) 的最大 \(a_i\) 即可(看有无被挡住
查询可用线段树和ST表

(早该学学ST表了,下午出个ST表的笔寄吧)

Code

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5;
int a[N], f[N][25], n, m; //st表

void init () {
    for (int j = 1; j < 23; j ++)
        for (int i = 1; i + (1 << j) - 1 <= m; i++) //m!!!
            f[i][j] = max(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);  // ST表具体实现
}

int query (int l, int r) {
    int k = __lg (r - l + 1);
    return max (f[l][k], f[r-(1<<k)+1][k]);
}

int main () {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i ++)   scanf("%d", &f[i][0]);
    init ();

    int q;
    cin >> q;
    while (q --) {
        int sx, sy, fx, fy, k;
        scanf("%d%d%d%d%d", &sx, &sy, &fx, &fy, &k);
        int dx = abs (fx - sx), dy = abs (fy - sy);

        if ((dx % k) || (dy % k)) {
            cout << "NO\n";
            continue;
        }

        bool suc = true;
        int maxn = sx + (n - sx)/k * k, l, r;
        if (sy < fy)    l = sy + 1, r = fy;
        else if (sy > fy)    l = fy, r = sy - 1;

        if (sy != fy && maxn <= query (l, r))  suc = false; 
         
        if (suc)    cout<<"YES"<<"\n";  
        else    cout << "NO\n";
    }
}

//n*m的方格,某些位置(1-am)被block
//可以上下左右走但是只能一次走k个
//q次询问,(sx,sy),(fx,fy),k  问能不能从s走到f呢

//统计曼哈顿距离

E. XOR Tree

题意

分析

Code

posted @ 2022-07-22 09:51  Sakana~  阅读(101)  评论(0编辑  收藏  举报