Educational Codeforces Round 25

Educational Codeforces Round 25

https://codeforces.com/contest/825
ABCD没有什么意思,阅读理解题比较无聊(((
EFG不难写,但是思维比较巧,知道就是知道,不知道就写不出emm

A. Binary Protocol

#include <bits/stdc++.h>

using namespace std;

int main () {
    int n;
    string s;
    cin >> n >> s;
    int len = 0;
    for (auto i : s) {
        if (i == '1')   len ++;
        else {
            cout << len;
            len = 0;
        }
    }
    cout << len;
}

B. Five-In-a-Row

#include <bits/stdc++.h>

using namespace std;
const int N = 15;
char a[N][N];
int n = 10;

bool check(int i, int j) {
    int cnt = 1;
    //横向
    cnt = 1;
    for (int k = j + 1; k <= n; k++) {
        if (a[i][k] == 'X')    cnt++;
        else    break;
    }
    for (int k = j - 1; k >= 1; k--) {
        if (a[i][k] == 'X')    cnt++;
        else    break;
    }
    if (cnt >= 5)   return true;

    //纵向
    cnt = 1;
    for (int k = i + 1; k <= n; k++) {
        if (a[k][j] == 'X')    cnt++;
        else    break;
    }
    for (int k = i - 1; k >= 1; k--) {
        if (a[k][j] == 'X')    cnt++;
        else    break;
    }
    if (cnt >= 5)   return true;

    //主对角线
    cnt = 1;
    for (int k = 1; k + i <= n; k++) {
        if (a[i + k][j + k] == 'X')    cnt++;
        else    break;
    }
    for (int k = 1; i - k >= 1; k++) {
        if (a[i - k][j - k] == 'X')    cnt++;
        else    break;
    }
    if (cnt >= 5)   return true;

    //副对角线
    cnt = 1;
    for (int k = 1; k + i <= n && j - k >= 1; k++) {
        if (a[i + k][j - k] == 'X')    cnt++;
        else    break;
    }
    for (int k = 1; i - k >= 1 && j + k <= n; k++) {
        if (a[i - k][j + k] == 'X')    cnt++;
        else    break;
    }
    if (cnt >= 5)   return true;

    return false;
}

int main() {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> a[i][j];
        }
    }


    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (a[i][j] == 'O')    continue;
            if (check (i, j)) {
                cout << "YES\n";
                return 0;
            }
        }
    }

    cout << "NO\n";
}

//若是放下之前就已经有能够连成的了

C. Multi-judge Solving

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

using namespace std;
const int N = 1e3 + 5;
ll a[N], n, k, ans;

int main() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++)    cin >> a[i];
    sort (a + 1, a + n + 1);
    for (int i = 1; i <= n; k = max (k, a[i++])) {
        if (a[i] <= 2 * k)      continue;
        while (k * 2 < a[i])    k *= 2, ans ++;
        //cout << k << ' ';
    }
    cout << ans << endl;
}

//自身是可以当作跳板的

D. Suitable Replacement

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

using namespace std;

int main() {
    string s, t;
    cin >> s >> t;
    map<char, int> mps, mpt;
    for (auto i : s)    mps[i]++;
    for (auto i : t)    mpt[i]++;
    mps['?'] = 0;
    for (auto &i : s) {
        if (i != '?')   continue;
        int minn = 1e9;
        char ch;
        for (char a = 'a'; a <= 'z'; a++) {
            if (1ll * minn * mpt[a] > mps[a]) {
                minn = mps[a] / mpt[a];
                ch = a;
            }
        }
        i = ch, mps[i] ++;
    }
    cout << s;
}

E. Minimal Labels

以为是差分约束,怎么是字典序最大的逆拓扑序??

// LUOGU_RID: 103196572
#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5, M = 3e5 + 5;//不是很懂为什么是这么大
int n, m, d[N], ans[N];
int h[N], e[M], ne[M], idx;

void add (int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void topsort(){
    priority_queue<int> q; //为什么是优先队列: 字典序最大的top序
    for(int i = 1;i <= n; ++i)    if(d[i] == 0) q.push(i);
    int tot = n;
    while(q.size()){
        int t = q.top();
        ans[t] = tot--;
        q.pop();
        for(int i = h[t];i != -1; i = ne[i]){
            int j = e[i];
            d[j] --;// j 的入度 --
            if(d[j] == 0) q.push(j); 
        }
    }
}

int main () {
    memset (h, -1, sizeof h);
    cin >> n >> m;
    while (m --) {
        int a, b; //a < b
        cin >> a >> b;
        add (b, a);
        d[a] ++;
    }
    topsort ();
    for (int i = 1; i <= n; i++)    cout << ans[i] << ' ';
}

//逆拓扑序从大到小排

F. String Compression

dp + kmp蛮不错的小题
涉及到对kmp的理解,求循环节那块
(可能比较板?!)
对后缀进行next数组求解

// LUOGU_RID: 103202632
#include  <bits/stdc++.h>

using namespace std;
const int N = 8005;
int f[N], cnt[N], nxt[N]; //f[i]: 压缩到i时的答案, cnt[i]: i的位数
char s[N];

void kmp(char *s, int len, int nxt[]) {
    //cout << s << endl;
    nxt[0] = nxt[1] = 0;
    for(int i = 1; i < len; ++i) {
        int j = nxt[i];
        while(j && s[i]!=s[j])  j=nxt[j];
        if (s[j] == s[i])   nxt[i+1] = j + 1;
        else    nxt[i+1] = 0;
    }
}

int main () {
    cin >> s;
    int n = strlen (s);
    for (int i = 1; i <= n; i++) {
        cnt[i] = cnt[i/10] + 1, f[i] = i + 1; //字符+个数1
    }
    for (int i = 0; i < n; i++) {
        kmp (s + i, n - i, nxt);  //截取i为起点的后缀[i,n)
        for (int j = 1; j + i <= n; j++) { //区间[i,i+j)
            int len = j - nxt[j]; //最长循环节
            if (j % len)    f[i+j] = min (f[i+j], f[i] + j + 1);
            else    f[i+j] = min (f[i+j], f[i] + len + cnt[j/len]);
        }
    }
    cout << f[n] << endl;
}


//dp + kmp(nxt数组)
//nxt[i]: 后缀i可以匹配的最长前缀
//[nxt[i],i]: 以i结尾的循环串

G. Tree Queries

取巧(思维!?)
以第一个黑点为根,\(a_i\) 记录 \(i\) 到根上最小点的编号,则所有点的求解都可转化为 \(a_i\)。分为在/不在同一根上,都是直接记录最小值即可。根作为中介已经能转化了。

// LUOGU_RID: 103207434
#include <bits/stdc++.h>

using namespace std;
const int N = 1e6 + 5, M = N * 2;
int a[N], n, q; //a[i]: i到根上最小的点的编号
int h[N], e[M], ne[M], idx;

void add (int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void dfs (int u, int fa) {
    for (int i = h[u]; ~i; i = ne[i]) {
        int j = e[i];
        if (j == fa)    continue;
        a[j] = min (j, a[u]);
        dfs (j, u);
    }
}

int main () {
    memset (h, -1, sizeof h);
     scanf ("%d%d", &n, &q);
    for (int i = 1; i < n; i++) {
        int a, b;
        scanf ("%d%d", &a, &b);
        add (a, b), add (b, a);
    }
    int lst = 0, ans = 1e9, fst = 0;
    while (q--) {
        int op, x;
        scanf ("%d%d", &op, &x);
        x = (x + lst) % n + 1;
        if (op == 1) {
            if (fst == 0)   a[x] = x, fst = 1, dfs (x, -1); //以第一个黑为根
            ans = min (ans, a[x]);
        }
        else {
            lst = min (ans, a[x]);
            printf ("%d\n", lst);
        }
    }
}

//在不在一条路上的都可以转化
posted @ 2023-02-27 20:32  Sakana~  阅读(21)  评论(0编辑  收藏  举报