Educational Codeforces Round 70 (Rated for Div. 2)

本文解析了Educational Codeforces Round 70(针对Div.2)的五道题目,包括二进制字符串匹配、十进制字符串操作、WASD字符串处理、1337字符串构造及字符串拼接统计,提供了详细的算法思路与代码实现。
摘要由CSDN通过智能技术生成

Educational Codeforces Round 70 (Rated for Div. 2)

题目链接

A. You Are Given Two Binary Strings...

注意到乘以一个\(2^k\)就相当于将二进制左移\(k\)位,然后贪心匹配就行了:找到\(t\)串最后一个\(1\)的位置,然后尽可能地去匹配\(s\)串后面的\(1\)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int T;
char s[N], t[N];
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> s + 1 >> t + 1;
        int n = strlen(s + 1), m = strlen(t + 1);
        int p = 1;
        for(int i = m; i >= 0; i--) {
            if(t[i] == '1') break;
            p++;
        }
        int ans = 0;
        for(int i = n - p + 1; i >= 0; i--) {
            if(s[i] == '1') break;
            ans++;
        }
        cout << ans << '\n';
    }
    return 0;
}
B. You Are Given a Decimal String...

\(bfs\)预处理出\(d[i][j][k][t]\),即用\([i,j]\)生成器,从数字\(k\)\(t\)的最小步数即可。

Code

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 10, M = 2e6 + 5;
int d[N][N][N][N];
bool vis[N];
char s[M];
void bfs(int x, int y, int z, int *d) {
    memset(vis, 0, sizeof(vis));
    queue <int> q; q.push(z);
    d[z] = 0;
    if(x > y) swap(x, y);
    while(!q.empty()) {
        int u = q.front(); q.pop();
        int v1 = u + y, v2 = u + x;
        if(v1 >= 10) v1 -= 10;
        if(v2 >= 10) v2 -= 10;
        if(!vis[v1]) {
            d[v1] = d[u] + 1;
            q.push(v1);
            vis[v1] = 1;
        }
        if(!vis[v2]) {
            d[v2] = d[u] + 1;
            q.push(v2);
            vis[v2] = 1;
        }
    }
}
void pre() {
    //k->t
    memset(d, -1, sizeof(d));
    for(int i = 0; i < 10; i++) {
        for(int j = 0; j < 10; j++) {
            for(int k = 0; k < 10; k++)
                bfs(i, j, k, d[i][j][k]);
        }
    }
//    cout << d[0][0][0][0];
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    pre();
    cin >> s + 1;
    int n = strlen(s + 1);
    for(int i = 0; i < 10; i++) {
        for(int j = 0; j < 10; j++) {
            int ans = 0;
            for(int k = 2; k <= n; k++) {
                if(d[i][j][s[k - 1] - '0'][s[k] - '0'] == -1) {
                    ans = -1; break;
                }
                ans += d[i][j][s[k - 1] - '0'][s[k] - '0'] - 1;
            }
            cout << ans << ' ';
        }
        cout << '\n';
    }
    return 0;
}
C. You Are Given a WASD-string...

\(W,S\)\(A,D\)是独立的,所以我们可以分开考虑。
现在只考虑\(S,W\)这种情况,模拟一下会发现我们可以将区间向下减少\(1\),当且仅当存在一个\(pos\),满足\(pos>maxpos_{up}\)\(pos<minpos_{down}\),此时我们在\(pos\)处插入一个\(W\)即可;其它情况也类似。
写起来的话这样写有点麻烦,可以直接找满足条件的数量关系。详见代码吧:

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int T;
char s[N];
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> s + 1;
        int nowx = 0, nowy = 0;
        int up = 0, down = 0, left = 0, right = 0;
        int dup = 0, ddown = 0, dleft = 0, dright = 0;
        int n = strlen(s + 1);
        for(int i = 1; i <= n; i++) {
            if(s[i] == 'D') nowy++;
            if(s[i] == 'W') nowx--;
            if(s[i] == 'A') nowy--;
            if(s[i] == 'S') nowx++;
            up = min(up, nowx);
            down = max(down, nowx);
            right = max(right, nowy);
            left = min(left, nowy);
            dup = max(dup, nowx - up);
            ddown = max(ddown, down - nowx);
            dleft = max(dleft, nowy - left);
            dright = max(dright, right - nowy);
        }
        int x = down - up + 1, y = right - left + 1;
        ll ans = 1ll * x * y;
        if(dup != ddown) ans = min(ans, 1ll * max(x - 1, 2) * y);
        if(dleft != dright) ans = min(ans, 1ll * x * max(y - 1, 2));
        cout << ans << '\n';
    }
    return 0;
}
D. Print a 1337-string...

构造题。
先构造出1337,然后考虑在后面加若干个3,最后再加一个7。假设3的个数为\(x\),那么现在的答案就为\(C(x,2)+1\)
我们选择尽量大的\(x\),满足\(C(x,2)+1\leq n_i\)
最后还会差一点,补一些7在1337后面就行了。
可以证明这样是符合题目限制条件的,只是卡得可能有点紧。

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
int n;
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> n;
        if(n == 1) {
            cout << "1337" << '\n';
            continue;
        }
        int x = 2;
        while(1ll * (x + 1) * x <= 2 * n - 2) x++;
        cout << "1337";
        ll tot = 1ll * x * (x - 1) / 2 + 1;
        n -= tot;
        for(int i = 1; i <= n; i++) cout << '7';
        for(int i = 3; i <= x; i++) cout << '3';
        cout << '7' << '\n';
    }
    return 0;
}
E. You Are Given Some Strings...

因为拼合两个串较为麻烦,考虑对于串\(t\)枚举分界点\(i\),求出\(f[i],g[i]\),分别表示以\(i\)为终点、起点的串中包含了多少串,之后直接统计即可。
包含关系可以结合\(fail\)指针来解决。对于\(f,g\),正反两次\(AC\)自动机即可。
代码如下:

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5, MAX = 26;
string t;
string s[N];
int n;
queue <int> q;
struct ACAM{
    int sz;
    int ch[N][MAX];
    int cnt[N], fail[N];
    void init() {
        sz = -1;
        newnode();
    }
    int newnode() {
        memset(ch[++sz], 0, sizeof(ch[sz]));
        cnt[sz] = fail[sz] = 0;
        return sz;
    }
    void insert(string s) {
        int u = 0;
        int l = s.length();
        for(int i = 0; i < l; i++) {
            int idx = s[i] - 'a';
            if(!ch[u][idx]) ch[u][idx] = newnode();
            u = ch[u][idx];
        }
        cnt[u]++;
    }
    void build() {
        while(!q.empty()) q.pop();
        for(int i = 0; i < 26; i++) {
            if(ch[0][i]) q.push(ch[0][i]);
        }
        while(!q.empty()) {
            int cur = q.front(); q.pop();
            cnt[cur] += cnt[fail[cur]];
            for(int i = 0; i < 26; i++) {
                if(ch[cur][i]) {
                    fail[ch[cur][i]] = ch[fail[cur]][i];
                    q.push(ch[cur][i]);
                } else {
                    ch[cur][i] = ch[fail[cur]][i];
                }
            }
        }
    }
    void query(string s, int *f) {
        int len = s.length();
        int u = 0;
        for(int i = 0; i < len; i++) {
            int idx = s[i] - 'a';
            u = ch[u][idx];
            f[i] = cnt[u];
        }
    }
}ac;
int f[N], g[N];
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> t >> n;
    int len = t.length();
    ac.init();
    for(int i = 1; i <= n; i++) {
        cin >> s[i];
        ac.insert(s[i]);
    }
    ac.build();
    ac.query(t, f);
    ac.init();
    reverse(t.begin(), t.end());
    for(int i = 1; i <= n; i++) {
        reverse(s[i].begin(), s[i].end());
        ac.insert(s[i]);
    }
    ac.build();
    ac.query(t, g);
    ll ans = 0;
    for(int i = 0; i < len - 1; i++) {
        ans += 1ll * f[i] * g[len - i - 2];
    }
    cout << ans;
    return 0;
}

转载于:https://www.cnblogs.com/heyuhhh/p/11332611.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值