CodeForces Gym 101190简要题解

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
                for (int i = x; i ^ y; i = par[i])
                    cir[cnt].pb(i);
            }
}

inline void Solve(int x)
{
    for (auto c : hav[x])
    {
        for (auto y : cir[c])
            if (y ^ x)
                f[y] = 1;
        for (auto y : cir[c])
            if (y ^ x)
                Solve(y);
        for (int i = 1; i < cir[c].size(); i ++)
        {
            int p = cir[c][i - 1], q = cir[c][i];
            ans.pb(Node(2, p, 1, 3));
            ans.pb(Node(1, p, q));
            ans.pb(Node(3, p, 1, 3));
            ans.pb(Node(2, p, 3, i == 1 ? 4 : 2));
        }
        int y = cir[c].back();
        ans.pb(Node(3, x, 1, 4));
        ans.pb(Node(2, x, 1, 2));
        ans.pb(Node(2, x, 4, 1));
    }
    for (auto y : adj[x])
        if (!f[y])
        {
            f[y] = 1, Solve(y);
            ans.pb(Node(2, y, 1, 3));
            ans.pb(Node(1, x, y));
            ans.pb(Node(3, x, 1, 3));
            ans.pb(Node(2, x, 3, 2));
        }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    n = Read(), m = Read();
    while (m --)
    {
        int x = Read();
        for (int i = 1; i <= x; i ++)
            a[i] = Read();
        for (int i = 1; i < x; i ++)
            adj[a[i]].pb(a[i + 1]), adj[a[i + 1]].pb(a[i]);
    }
    Dfs(1);
    f[1] = 1;
    Solve(1);
    printf("%d\n", ans.size());
    for (auto e : ans)
        if (e.opt == 1)
            printf("j %d %d\n", e.a, e.b);
        else if (e.opt == 2)
            printf("r %d %d %d\n", e.a, e.b, e.c);
        else if (e.opt == 3)
            printf("c %d %d %d\n", e.a, e.b, e.c);
}

Delight for a Cat

考虑费用流,一个点如果选择睡觉那就会影响之后的k个东西,直接跳k步,否则直接走到i+1,求一个流量为max的流即可。

#define FIO "delight"
#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 = 1005;
const int MAXM = 6005;
const int INF = 0x3f3f3f3f;

namespace Flow
{
    struct edge
    {
        int p, v, w, c;
    } e[MAXM];

    int V, S, T, hed[MAXN], e_cnt = 1;
    LL ans, dis[MAXN];
    bool vis[MAXN];

    inline void Init(int n)
    {
        V = n, e_cnt = 1;
        for (int i = 0; i < V; i ++)
            hed[i] = 0;
    }

    inline void Add(int x, int y, int w, int c) { e[++ e_cnt] = {y, hed[x], w, c}; hed[x] = e_cnt; }
    inline void Addedge(int x, int y, int w, int c) { Add(x, y, w, c); Add(y, x, 0, -c); }

    inline bool Spfa()
    {
        for (int i = 0; i < V; i ++)
            dis[i] = 1LL << 60, vis[i] = 0;
        queue <int> q;
        dis[S] = 0; q.push(S);
        while (!q.empty())
        {
            int x = q.front(); q.pop(); vis[x] = 0;
            for (int i = hed[x]; i; i = e[i].v)
                if (e[i].w && dis[e[i].p] > dis[x] + e[i].c)
                {
                    dis[e[i].p] = dis[x] + e[i].c;
                    if (!vis[e[i].p])
                        vis[e[i].p] = 1, q.push(e[i].p);
                }
        }
        return dis[T] < 1LL << 60;
    }

    inline int Dfs(int x, int f)
    {
        vis[x] = 1;
        if (x == T)
            return f;
        int ret = 0, d;
        for (int i = hed[x]; i; i = e[i].v)
            if (e[i].w && dis[e[i].p] == dis[x] + e[i].c && !vis[e[i].p])
            {
                d = Dfs(e[i].p, min(f - ret, e[i].w));
                e[i].w -= d; e[i ^ 1].w += d; ret += d;
                if (ret == f)
                    return ret;
            }
        return ret;
    }

    inline int Solve()
    {
        int ret = 0;
        while (Spfa())
        {
            vis[T] = 1;
            while (vis[T])
            {
                for (int i = 0; i < V; i ++)
                    vis[i] = 0;
                int d = Dfs(S, INF);
                ret += d; ans += d * dis[T];
            }
        }
        return ret;
    }
}

int n, k, p, q, a[MAXN];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    using namespace Flow;
    n = Read(), k = Read(), p = k - Read(), q = Read();
    Flow::Init(n + 3), Flow::T = n + 2;
    for (int i = 1; i <= n; i ++)
        a[i] -= Read(), ans += a[i];
    for (int i = 1; i <= n; i ++)
        a[i] += Read();
    for (int i = 1; i <= n; i ++)
        Addedge(i, i + k <= n ? i + k : T, 1, -a[i]);
    for (int i = 1; i <= n; i ++)
        Addedge(i, i == n ? T : i + 1, p - q, 0);
    for (int i = 1; i <= k; i ++)
        Addedge(n + 1, i, INF, 0);
    Addedge(S, n + 1, p, 0);
    Solve();
    printf("%lld\n", -ans);
    for (int i = 1; i <= n; i ++)
        putchar(e[i << 1].w ? 'S' : 'E');
    putchar(10);
    return 0;
}

Expect to Wait

随便推一推发现是个一次函数的形式,离线之后打上差分标记。

#define FIO "expect"
#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 = 100005;

int n, m, t[MAXN], c[MAXN], l[MAXN];
LL p, q, a[MAXN], b[MAXN], ans[MAXN];
pii e[MAXN];
char ch[2];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    n = Read(), m = Read();
    for (int i = 1, x, y; i <= n; i ++)
    {
        scanf("%s", ch);
        if (ch[0] == '+')
            t[i] = Read(), c[i] = Read();
        else
            t[i] = Read(), c[i] = -Read();
    }
    for (int i = 1; i <= m; i ++)
        e[i].xx = Read(), e[i].yy = i;
    sort(e + 1, e + m + 1);
    for (int i = 1; i <= m; i ++)
        l[i] = e[i].xx;
    for (int i = 1, s = 0, d; i <= n; i ++)
    {
        s += c[i], d = t[i + 1] - t[i];
        if (s < 0)
        {
            int p = lower_bound(l + 1, l + m + 1, -s) - l;
            if (i ^ n)
                a[0] -= d, b[0] -= 1LL * d * s, a[p] += d, b[p] += 1LL * d * s;
            else
                for (int j = 1; j < p; j ++)
                    ans[e[j].yy] = -1;
        }
    }
    for (int i = 0; i <= m; i ++)
    {
        p += a[i], q += b[i];
        if (~ans[e[i].yy])
            ans[e[i].yy] = p * e[i].xx + q;
    }
    for (int i = 1; i <= m; i ++)
        if (ans[i] == -1)
            puts("INFINITY");
        else
            printf("%lld\n", ans[i]);
    return 0;
}

Foreign Postcards

暴力想法是枚举一对(i,j),然后用个后缀和来优化一下。

#define FIO "foreign"
#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;

long double ans;
int n, a[MAXN];
LL p, q, c, d;
char s[MAXN];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    scanf("%s", s + 1); n = strlen(s + 1);
    for (int i = 1; i <= n; i ++)
        a[i] = s[i] == 'W';
    for (int i = 1; i <= n; i ++)
        c += a[i], d += !a[i], p += c, q += d;
    for (int i = 0; i < n; i ++)
    {
        double r = i ? 1.0 / (1LL * (n - i) * (n - i + 1)) : 1.0 / n;
        ans += r * (a[i + 1] ? q : p);
        p -= a[i + 1] * (n - i);
        q -= (!a[i + 1]) * (n - i);
    }
    return printf("%.10Lf\n", ans), 0;
}

Game on Graph

考虑记f(i,j)表示当前在i,第j个人行动,是否游戏会结束,g(i,j)表示游戏是否会让A(第一目标是赢的那个人)获胜,然后倒着递推。

#define FIO "game"
#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 = 100005;

vector <int> adj[MAXN], rev[MAXN];
bool a[MAXN][2], b[MAXN][2];
int n, m, ql, qr, d[MAXN];
pii q[MAXN << 1];

inline void Solve(bool f[MAXN][2])
{
    ql = qr = 0;
    for (int i = 1; i <= n; i ++)
        for (int j = 0; j < 2; j ++)
            if (f[i][j])
                q[++ qr] = mp(i, j);
    for (int i = 1; i <= n; i ++)
        d[i] = adj[i].size();
    while (ql ^ qr)
    {
        int x = q[++ ql].xx, p = q[ql].yy;
        if (p)
        {
            for (auto y : rev[x])
                if (!f[y][0] && !-- d[y])
                    f[y][0] = 1, q[++ qr] = mp(y, 0);
        }
        else
            for (auto y : rev[x])
                if (!f[y][1])
                    f[y][1] = 1, q[++ qr] = mp(y, 1);
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    n = Read(), m = Read();
    for (int i = 1, x, y; i <= m; i ++)
        x = Read(), y = Read(), adj[x].pb(y), rev[y].pb(x);
    for (int i = 1; i <= n; i ++)
        if (adj[i].empty())
            a[i][0] = a[i][1] = b[i][0] = 1;
    Solve(a);
    Solve(b);
    for (int i = 1; i <= n; i ++)
        if (b[i][0])
            putchar('L');
        else if (!a[i][0])
            putchar('D');
        else
            putchar('W');
    putchar(10);
    for (int i = 1; i <= n; i ++)
        if (b[i][1])
            putchar('W');
        else if (a[i][1])
            putchar('L');
        else
            putchar('D');
    putchar(10);
    return 0;
}

Hard Refactoring

模拟。

#define FIO "hard"
#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 = 100005;

int a[MAXN], n = 1 << 15;
vector <pii> ans;
char s[MAXN];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    while (fgets(s, MAXN, stdin))
    {
        int l, r;
        if (sscanf(s, "x >= %d && x <= %d", &l, &r) ^ 2)
            if (sscanf(s, "x >= %d", &l) ^ 1)
                sscanf(s, "x <= %d", &r), l = -n;
            else
                r = n - 1;
        if (l > r)
            continue;
        a[l + n] ++, a[r + n + 1] --;
    }
    for (int i = 1; i < MAXN; i ++)
        a[i] += a[i - 1];
    for (int i = 0; i < MAXN; i ++)
        if (a[i])
        {
            int p = i;
            while (a[p + 1])
                p ++;
            ans.pb(mp(i - n, p - n));
            i = p;
        }
    if (ans.empty())
        return puts("false"), 0;
    if (ans.size() == 1 && ans[0].xx == -n && ans[0].yy == n - 1)
        return puts("true"), 0;
    for (int i = 0; i < ans.size(); i ++)
    {
        pii x = ans[i];
        if (x.xx == -n)
            printf("x <= %d", x.yy);
        else if (x.yy == n - 1)
            printf("x >= %d", x.xx);
        else
            printf("x >= %d && x <= %d", x.xx, x.yy);
        if (i < ans.size() - 1)
            puts(" ||");
    }
    putchar(10);
    return 0;
}

Indiana Jones and the Uniform Cave

挺厉害的交互题。
考虑用DFSL表示不在栈中的点,R表示在栈中的点,C表示没经过的点。
如果一个点走到了不在栈中的点,那么我们先向上跳(L)再向下跳(R),就知道深度了。
在栈中的也是走两遍就知道深度了。

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

int n, m, L = 0, R = 1, C = 2, adj[25][25];

inline int Next()
{
    char s[15];
    scanf("%s", s);
    if (s[0] == 'l')
        return L;
    if (s[0] == 'r')
        return R;
    if (s[0] == 'c')
        return C;
    exit(0);
}

inline int Print(int p, int t, int v)
{
    printf("%d %s %d\n", p, t ? "right" : "left", v);
    fflush(stdout);
    return Next();
}

inline void Dfs(int x, int dep)
{
    for (int i = 0; i < m; i ++)
    {
        int val = Print(1, R, 1), cnt = 0;
        if (val == C)
            Dfs(++ n, adj[x][i] = dep + 1), val = L;
        if (val == L)
        {
            for (; Print(0, L, 0) == L; );
            for (; Print(0, R, 0) == R; cnt ++);
            for (; Print(0, L, 0) == L; );
            for (int i = 1; i <= cnt; i ++)
                Print(0, R, 0);
            adj[x][i] = dep - cnt;
        }
        else
        {
            for (; Print(0, L, 0) == R; cnt ++);
            for (int i = 0; i <= cnt; i ++)
                Print(0, R, 0);
            for (int i = 1; i <= cnt; i ++)
                Print(0, R, 0);
            adj[x][i] = dep - cnt;
        }
    }
    if (x ^ 1)
    {
        int pos = -1, val;
        for (int i = 0; i < m; i ++)
            if (!~pos || adj[x][i] < adj[x][pos])
                pos = i;
        val = Print((pos + 1) % m, L, (pos + 1) % m);
        for (; val == L; val = Print(0, L, 0));
        for (; Print(0, R, 0) == R; );
    }
}

int main()
{
    m = Read();
    Next();
    Dfs(++ n, 1);
    return 0;
}

Jenga Boom

暴力。

#define FIO "jenga"
#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 = 5005;

int n, m, h, w, l[MAXN], r[MAXN], c[MAXN], s[MAXN];
bool f[MAXN][MAXN << 1];

inline bool chk()
{
    LL cnt[2] = {0, 0}, sum[2] = {0, 0};
    for (int i = h, cur = i & 1; i > 1; i --, cur ^= 1)
    {
        cnt[cur] += c[i], sum[cur] += s[i];
        if ((sum[cur ^ 1] + cnt[cur] * n) <= (cnt[0] + cnt[1]) * (l[i - 1] * 2 - 2))
            return 1;
        if ((sum[cur ^ 1] + cnt[cur] * n) >= (cnt[0] + cnt[1]) * (r[i - 1] * 2))
            return 1;
    }
    return 0;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    n = Read(), w = Read(), h = Read(), m = Read();
    for (int i = 1; i <= h; i ++)
        l[i] = 1, r[i] = n, c[i] = n, s[i] = n * n;
    for (int i = 1; i <= m; i ++)
    {
        int x = Read(), y = Read();
        f[x][y] = 1;
        s[x] -= y * 2 - 1;
        if (-- c[x])
        {
            while (f[x][l[x]])
                l[x] ++;
            while (f[x][r[x]])
                r[x] --;
        }
        else if (x == h)
            h --;
        else
            return printf("yes\n%d\n", i), 0;
        if (chk())
            return printf("yes\n%d\n", i), 0;
    }
    return puts("no"), 0;
}

Kids Designing Kids

三个图异或为0,那么左上角一定有两个能匹配,枚举一下3种情况验证就好了。

#define FIO "kids"
#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;
}

set <pii> A, B, C;
pii a, b, c;
char ch[1005];

inline void Init(set <pii> &S, pii &s)
{
    int n = Read(), m = Read(), f = 0;
    for (int i = 1; i <= n; i ++)
    {
        scanf("%s", ch + 1);
        for (int j = 1; j <= m; j ++)
            if (ch[j] == '*')
            {
                if (!f)
                    f = 1, s = mp(-i, -j);
                S.insert(mp(i + s.xx, j + s.yy));
            }
    }
}

inline bool Chk(set <pii> &A, pii &a, set <pii> &B, pii &b, set <pii> &C, pii &c)
{
    set <pii> S;
    for (auto x : A)
        S.insert(x);
    for (auto x : B)
        if (S.find(x) != S.end())
            S.erase(x);
        else
            S.insert(x);
    if (S.size() != C.size())
        return 0;
    pii s = *S.begin();
    for (auto x : C)
        if (S.find(mp(x.xx + s.xx, x.yy + s.yy)) == S.end())
            return 0;
    c = mp(c.xx + s.xx, c.yy + s.yy);
    return 1;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    Init(A, a); Init(B, b); Init(C, c);
    if (Chk(A, a, B, b, C, c) || Chk(A, a, C, c, B, b) || Chk(B, b, C, c, A, a))
        return printf("YES\n%d %d\n", b.yy - a.yy, b.xx - a.xx), 0;
    return puts("NO"), 0;
}

List of Primes

注意到最后质数不会很大,预处理每个质数的贡献就可以开始爆搜了。

#define FIO "list"
#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 = 2340;

LL f[MAXN][MAXN], g[MAXN][MAXN], l, r;
int n, cnt, now, p[MAXN], v[MAXN], use[MAXN];
bool chk[MAXN];
char ch[MAXN];

inline void Init()
{
    for (int i = 2; i < MAXN; i ++)
    {
        if (!chk[i])
            p[++ n] = i;
        for (int j = 1; i * p[j] < MAXN; j ++)
        {
            chk[i * p[j]] = 1;
            if (i % p[j] == 0)
                break;
        }
    }
}

inline void Print(LL l, LL r)
{
    int tot = 0, cur;
    ch[++ tot] = '[';
    for (int i = 1, t; i <= cnt; i ++)
    {
        t = p[use[i]], cur = tot + v[use[i]];
        while (t)
            ch[cur --] = t % 10 + '0', t /= 10;
        tot += v[use[i]];
        ch[++ tot] = ',', ch[++ tot] = ' ';
    }
    ch[-- tot] = ']', ch[++ tot] = ',', ch[++ tot] = ' ';
    for (LL i = l; i <= min(r, (LL)tot); i ++)
        putchar(ch[i]);
}

inline void Dfs(int sum, LL l, LL r)
{
    int i;
    for (i = use[cnt] + 1; i <= n && p[i] < sum; i ++)
    {
        LL t = f[sum - p[i]][i + 1] * (now + v[i] + 2) + g[sum - p[i]][i + 1];
        if (t < l)
            l -= t, r -= t;
        else
        {
            use[++ cnt] = i, now += v[i] + 2;
            Dfs(sum - p[i], l, r);
            cnt --, now -= v[i] + 2;
            l = 1, r -= t;
            if (r <= 0)
                return ;
        }
    }
    if (p[i] == sum)
        use[++ cnt] = i, Print(l, r), cnt --;
    return ;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    cin >> l >> r;
    Init();
    for (int i = 1; i <= n; i ++)
        v[i] = p[i] >= 1000 ? 4 : (p[i] >= 100 ? 3 : (p[i] >= 10 ? 2 : 1)), f[p[i]][i] = 1, g[p[i]][i] = v[i] + 4;
    for (int i = 2; i < MAXN; i ++)
        for (int j = n; j; j --)
        {
            f[i][j] += f[i][j + 1];
            g[i][j] += g[i][j + 1];
            if (i >= p[j])
                f[i][j] += f[i - p[j]][j + 1], g[i][j] += g[i - p[j]][j + 1] + f[i - p[j]][j + 1] * (v[j] + 2);
        }
    for (int i = 2; i < MAXN; i ++)
    {
        if (g[i][1] < l)
            l -= g[i][1], r -= g[i][1];
        else
        {
            Dfs(i, l, r);
            l = 1, r -= g[i][1];
            if (r <= 0)
                return 0;
        }
    }
}

Mole Tunnels

暴力是费用流。
完全二叉树深度是log的,模拟一下费用流就好了。

#define FIO "mole"
#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 = 300005;

int n, m, c[MAXN], f[MAXN], g[MAXN], h[MAXN], p[MAXN], ans;

inline void Upd(int x)
{
    f[x] = 1 << 30, p[x] = 0;
    if (c[x])
        f[x] = 0, p[x] = x;
    if ((x << 1) <= n && f[x] > f[x << 1] + (h[x << 1] ? -1 : 1))
        f[x] = f[x << 1] + (h[x << 1] ? -1 : 1), p[x] = p[x << 1];
    if ((x << 1 | 1) <= n && f[x] > f[x << 1 | 1] + (h[x << 1 | 1] ? -1 : 1))
        f[x] = f[x << 1 | 1] + (h[x << 1 | 1] ? -1 : 1), p[x] = p[x << 1 | 1];
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#else
    freopen(FIO".in", "r", stdin);
    freopen(FIO".out", "w", stdout);
#endif
    n = Read(), m = Read();
    for (int i = 1; i <= n; i ++)
        c[i] = Read();
    for (int i = n; i; i --)
        Upd(i);
    while (m --)
    {
        int x = Read(), y, l, cur = 0, ret = 1 << 30;
        for (int i = x; i; cur += g[i] ? -1 : 1, i >>= 1)
            if (f[i] + cur < ret)
                ret = f[i] + cur, l = i;
        c[y = p[l]] --;
        for (int i = x; i ^ l; i >>= 1)
            if (g[i])
                g[i] --;
            else
                h[i] ++;
        for (int i = y; i ^ l; i >>= 1)
            if (h[i])
                h[i] --;
            else
                g[i] ++;
        for (int i = x; i; i >>= 1)
            Upd(i);
        for (int i = y; i; i >>= 1)
            Upd(i);
        printf("%d\n", ans += ret);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值