CodeForces Gym 101190简要题解

这篇博客详细介绍了CodeForces Gym 101190比赛中的多个算法问题,包括Abbreviation、Binary Code、Cactus Construction等题目。博主分享了各种解题策略,如模拟、暴力枚举、费用流等,并提到了一些优化技巧,如使用 Trie 树、后缀和以及2-SAT。通过这些解析,读者可以了解到如何解决这些算法挑战。
摘要由CSDN通过智能技术生成

NEERC天天被搬还是做了好了。

Abbreviation

模拟。

#define FIO "abbreviation"
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int MAXN = 500005;

int n, p[MAXN];
string t[MAXN];
char s[MAXN];

inline bool In(int x, int l, int r)
{
    return x >= l && x <= r;
}

inline int Find(int x)
{
    if (!In(s[x], 'A', 'Z') || !In(s[x + 1], 'a', 'z'))
        return 0;
    for (x ++; In(s[x], 'a', 'z'); x ++);
    if (In(s[x], 'A', 'Z'))
        return 0;
    return x;
}

inline int Chk(int x)
{
    int y, z;
    if (!(y = Find(x)) || s[y] != ' ' || !(z = Find(y + 1)))
        return 0;
    t[x] += s[x], t[x] += s[y + 1];
    while (true)
    {
        if (s[z] != ' ' || !(y = Find(z + 1)))
            return z - 1;
        t[x] += s[z + 1];
        z = y;
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    for (char c = getchar(); ~c; c = getchar())
        s[++ n] = c;
    for (int i = 1, j; i <= n; i ++)
        if (!In(s[i - 1], 'A', 'Z') && !In(s[i - 1], 'a', 'z'))
            if (j = Chk(i))
                p[i] = 1, p[j] = 2, i = j;
    for (int i = 1; i <= n; i ++)
    {
        if (p[i] == 1)
            printf("%s (", t[i].c_str());
        putchar(s[i]);
        if (p[i] == 2)
            putchar(')');
    }
}

Binary Code

暴力是枚举两个点的两种状态,看是否一个是另一个的前缀,跑2-SAT。
考虑用trie树优化建边,分别是前缀和和后缀和(表示选没选)。

#define FIO "binary"
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int MAXN = 1000005;
const int MAXM = 4000005;

int n, tot, len, cnt, num, scc[MAXM], par[MAXN], pos[MAXN], st[MAXN], ed[MAXN], tst[MAXN], ted[MAXN], dfn[MAXM], nxt[MAXN][2];
vector <int> adj[MAXM], vec[MAXN], G[MAXM];
char s[MAXN], ch[MAXN];
bool res[MAXN];

inline void Add(int p)
{
    int cur = 0;
    for (int i = 1; i <= len; cur = nxt[cur][s[i ++] - '0'])
        if (!nxt[cur][s[i] - '0'])
            par[nxt[cur][s[i] - '0'] = ++ cnt] = cur;
    pos[p] = cur;
    vec[cur].pb(p);
}

inline void Build()
{
    for (int i = 1; i <= cnt; i ++)
        if (!vec[i].empty())
        {
            for (int j = 0; j < vec[i].size(); j ++)
                if (!j)
                    adj[++ tot].pb(vec[i][j] ^ 1);
                else
                    adj[vec[i][j]].pb(tot), adj[tot + 1].pb(tot), adj[++ tot].pb(vec[i][j] ^ 1);
            tst[i] = tot;
            for (int j = 0; j < vec[i].size(); j ++)
                if (!j)
                    adj[vec[i][j]].pb(++ tot);
                else
                    adj[tot].pb(vec[i][j] ^ 1), adj[tot].pb(tot + 1), adj[vec[i][j]].pb(++ tot);
            ted[i] = tot;
        }
    for (int i = 2; i <= (n << 1 | 1); i ++)
        for (int j = par[pos[i]]; j; j = par[j])
            if (!vec[j].empty())
                adj[i].pb(tst[j]), adj[ted[j]].pb(i ^ 1);
}

int sta[MAXM], low[MAXM], tim, tp;

inline void Dfs(int x)
{
    dfn[x] = low[x] = ++ tim;
    sta[++ tp] = x;
    for (auto y : adj[x])
        if (!dfn[y])
            Dfs(y), low[x] = min(low[x], low[y]);
        else if (!scc[y])
            low[x] = min(low[x], dfn[y]);
    if (dfn[x] == low[x])
    {
        int cur = 0; num ++;
        while (cur ^ x)
            scc[cur = sta[tp --]] = num;
    }
}

int vis[MAXM], opp[MAXM], deg[MAXM], q[MAXM], ql, qr;

inline void Print()
{
    for (int i = 1; i <= n; i ++)
        opp[scc[i << 1]] = scc[i << 1 | 1], opp[scc[i << 1 | 1]] = scc[i << 1];
    for (int x = 2; x <= tot; x ++)
        for (auto y : adj[x])
            if (scc[x] ^ scc[y])
                G[scc[y]].pb(scc[x]), deg[scc[x]] ++;
    for (int i = 1; i <= num; i ++)
        if (!deg[i])
            q[++ qr] = i;
    while (ql ^ qr)
    {
        int x = q[++ ql];
        if (!vis[x])
             vis[x] = 1, vis[opp[x]] = -1;
        for (auto y : G[x])
            if (!-- deg[y])
                q[++ qr] = y;
    }
    for (int i = 2; i <= (n << 1 | 1); i ++)
        if (~vis[scc[i]])
            res[i >> 1] = i & 1;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    n = Read(), tot = n << 1 | 1;
    for (int i = 1, t = 1; i <= n; i ++)
    {
        scanf("%s", s + 1), len = strlen(s + 1);
        st[i] = t;
        for (int j = 1; j <= len; j ++)
            ch[t ++] = s[j];
        ed[i] = t;
        for (int j = 1; j <= len; j ++)
            if (s[j] == '?')
            {
                s[j] = '0', Add(i << 1);
                s[j] = '1', Add(i << 1 | 1);
                break;
            }
            else if (j == len)
                Add(i << 1), Add(i << 1 | 1);
    }
    Build();
    for (int i = 2; i <= tot; i ++)
        if (!dfn[i])
            Dfs(i);
    for (int i = 1; i <= n; i ++)
        if (scc[i << 1] == scc[i << 1 | 1])
            return puts("NO"), 0;
    puts("YES");
    Print();
    for (int i = 1; i <= n; putchar(10), i ++)
        for (int j = st[i]; j < ed[i]; j ++)
            if (ch[j] == '?')
                putchar(res[i] + '0');
            else
                putchar(ch[j]);
    return 0;
}

Cactus Construction

先把所有环和桥边分开,然后随便构造一下就好了。
详见代码。

#define FIO "cactus"
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

inline int Read()
{
    int x = 0, f = 1, c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            f = -1;
    for (;  isdigit(c); c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

const int MAXN = 50005;

struct Node
{
    int opt, a, b, c;

    Node(int _opt = 0, int _a = 0, int _b = 0, int _c = 0)
    {
        opt = _opt, a = _a, b = _b, c = _c;
    }
};

int n, m, tim, cnt, par[MAXN], a[MAXN], dfn[MAXN];
vector <int> adj[MAXN], hav[MAXN], cir[MAXN];
vector <Node> ans;
bool f[MAXN];

inline void Dfs(int x)
{
    dfn[x] = ++ tim;
    for (auto y : adj[x])
        if (y ^ par[x])
            if (!dfn[y])
                par[y] = x, Dfs(y);
            else if (dfn[y] < dfn[x])
            {
                hav[y].pb(++ cnt);
                cir[cnt].pb(y);
                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值