CodeForces Gym 101620简要题解

Assignment Algorithm

模拟。

#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 = 55;

char a[MAXN][MAXN];
int n, m;

inline void Solve(char c)
{
    vector <pii> row;
    int cnt_1 = 0, cnt_2 = 0, t = 1, l = 0, r = 0;
    for (int j = 0; j < 11; j ++)
        cnt_1 += a[1][j] == '-', cnt_2 += a[n / 2 + 2][j] == '-';
    if (cnt_1 || cnt_2)
    {
        if (cnt_1)
            row.pb(mp(cnt_1, 1));
        if (cnt_2)
            row.pb(mp(cnt_2, n / 2 + 2));
    }
    else
    {
        for (int i = 0; i < n + 3; i ++)
        {
            int cnt = 0;
            for (int j = 0; j < 11; j ++)
                cnt += a[i][j] == '-';
            if (cnt)
                row.pb(mp(cnt, i));
        }
    }
    sort(row.begin(), row.end(), greater <pii> ());
    for (int i = 1; i < row.size(); i ++)
        if (row[i].xx == row[0].xx)
            t = i + 1;
    for (int i = 0; i < t; i ++)
        row[i].xx = min(min(row[i].yy, n + 2 - row[i].yy), abs(row[i].yy - (n / 2 + 1)));
    sort(row.begin(), row.begin() + t);
    for (int i = 0; i < n + 3; i ++)
    {
        for (int j = 0; j < 5; j ++)
            l += a[i][j] == '-';
        for (int j = 6; j < 11; j ++)
            r += a[i][j] == '-';
    }
    int idx = row[0].yy;
    if (a[idx][4] == '-' || a[idx][6] == '-')
    {
        if (a[idx][4] != '-')
            a[idx][6] = c;
        else if (a[idx][6] != '-')
            a[idx][4] = c;
        else if (l >= r)
            a[idx][4] = c;
        else
            a[idx][6] = c;
    }
    else if (a[idx][2] == '-' || a[idx][8] == '-')
    {
        if (a[idx][2] != '-')
            a[idx][8] = c;
        else if (a[idx][8] != '-')
            a[idx][2] = c;
        else if (l >= r)
            a[idx][2] = c;
        else
            a[idx][8] = c;
    }
    else if (a[idx][0] == '-' || a[idx][10] == '-')
    {
        if (a[idx][0] != '-')
            a[idx][10] = c;
        else if (a[idx][10] != '-')
            a[idx][0] = c;
        else if (l >= r)
            a[idx][0] = c;
        else
            a[idx][10] = c;
    }
    else if (a[idx][5] == '-')
    {
        a[idx][5] = c;
    }
    else
    {
        if (a[idx][1] != '-')
            a[idx][9] = c;
        else if (a[idx][9] != '-')
            a[idx][1] = c;
        else if (l >= r)
            a[idx][1] = c;
        else
            a[idx][9] = c;
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read();
    for (int i = 0; i < n + 3; i ++)
        scanf("%s", a[i]);
    for (int i = 0; i < m; i ++)
        Solve(i + 'a');
    for (int i = 0; i < n + 3; i ++, putchar(10))
        for (int j = 0; j < 11; j ++)
            putchar(a[i][j]);
    return 0;
}

Buffalo Barricades

从上到下扫描线,用 set 维护当前的情况,并记录每个点的父亲,最后并查集扫一遍维护。

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

struct Event
{
    int typ, x, y, i;
    bool operator < (const Event &b) const
    {
        return y > b.y || (y == b.y && typ > b.typ);
    }
} a[MAXN << 1];

int n, m, f[MAXN], tmp[MAXN], tag[MAXN], ans[MAXN], par[MAXN];
set <pii> s;

inline int Find(int x)
{
    while (x ^ f[x])
        x = f[x] = f[f[x]];
    return x;
}

inline void Merge(int x, int y)
{
    if (x ^ y)
        f[x] = y, tag[y] += tag[x];
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1; i <= n; i ++)
        a[i].x = Read(), a[i].y = Read(), a[i].i = i, a[i].typ = 1;
    m = Read();
    for (int i = n + 1; i <= n + m; i ++)
        a[i].x = Read(), a[i].y = Read(), a[i].i = i - n, a[i].typ = 2;
    sort(a + 1, a + n + m + 1);
    for (int i = 1; i <= n + m; i ++)
        if (a[i].typ == 1)
        {
            auto it = s.lower_bound(mp(a[i].x, -1));
            if (it != s.end())
                tmp[it -> yy] ++;
        }
        else
        {
            auto it = s.insert(mp(a[i].x, a[i].i)).xx, jt = it;
            if (jt != -- s.end())
                par[a[i].i] = (++ jt) -> yy;
            while (it != s.begin())
            {
                jt = it, jt --;
                if (jt -> yy > a[i].i)
                    s.erase(jt);
                else
                    break;
            }
        }
    for (int i = 1; i <= m; i ++)
        f[i] = i;
    for (int i = m; i; i --)
        ans[i] = tag[Find(i)] += tmp[i], Merge(Find(i), Find(par[i]));
    for (int i = 1; i <= m; i ++)
        printf("%d\n", ans[i]);
    return 0;
}

Cumulative Code

fk(x) 表示 k 层的子树的prufer序列和, f(x)=ax+bx2+c ,然后就可以递推了。

询问的时候记忆化搜索,将 k 层及以下的情况记下来,注意一些边界情况。

#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 = 32780;

struct Node
{
    LL a, b, c;
    Node(LL a = 0, LL b = 0, LL c = 0):a(a), b(b), c(c) {}
    Node operator + (const Node &d) const { return Node(a + 2 * d.a + d.b, b, c + d.c); };
    Node operator - (const Node &d) const { return Node(a + 2 * d.a + d.b, b, c + d.c + d.a); }
} f[16][MAXN];

int tim, vis[16][MAXN];

inline Node Solve(int n, int a, int d, int m, bool p)
{
    if (n == 1)
        return Node(0, 1, 0);
    bool mem = n <= 15 && a + d * m >= (1 << n) - 1 && p;
    if (mem && vis[n][a] == tim)
        return f[n][a];
    Node ret(0, 0, 0);
    int cur = a;
    if (cur < (1 << n - 1) - 1 && m)
    {
        int t = min(m, ((1 << n - 1) - 1 - cur - 1) / d + 1);
        ret = ret + Solve(n - 1, cur, d, t, true), cur += t * d, m -= t;
    }
    cur -= (1 << n - 1) - 1;
    if (!p)
    {
        if (!cur && m)
            m --, cur += d, ret.a += 2, ret.c ++;
        cur --;
    }
    if (cur < (1 << n - 1) - 1 && m)
    {
        int t = min(m, ((1 << n - 1) - 1 - cur - 1) / d + 1);
        ret = ret - Solve(n - 1, cur, d, t, p), cur += t * d, m -= t;
    }
    cur -= (1 << n - 1) - 1;
    if (p && m)
        ret.b ++;
    if (mem)
        vis[n][a] = tim, f[n][a] = ret;
    return ret;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    int n = Read(), q = Read();
    while (q --)
    {
        int a = Read() - 1, d = Read(), m = Read();
        tim ++;
        Node ret = Solve(n, a, d, m, false);
        printf("%lld\n", ret.a + ret.c);
    }
    return 0;
}

Donut Drone

(x,0) c 次的情况记下来,询问可以暴力。

考虑修改,倒着推回去,不难发现最后一定是一段区间被影响了,也可以暴力维护。

#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 = 2005;

int n, m, q, tim, cur_x, cur_y, vis[MAXN], lst[MAXN], nxt[MAXN], a[MAXN][MAXN];

inline int R(int x) { x %= n; return x < 0 ? x + n : x; }
inline int C(int x) { x %= m; return x < 0 ? x + m : x; }

inline int FindNext(int x, int y)
{
    int val = -1, ret = -1;
    for (int i = x - 1; i <= x + 1; i ++)
        if (val < a[R(i)][C(y + 1)])
            ret = i, val = a[R(i)][C(y + 1)];
    return ret;
}

inline int Jump(int x, int y)
{
    for (; y < m; x = R(FindNext(x, y ++)));
    return x;
}

inline int Move(int t)
{
    if (t >= m - cur_y)
        while (cur_y)
            cur_x = R(FindNext(cur_x, cur_y)), cur_y = C(cur_y + 1), t --;
    tim ++;
    while (t >= m)
    {
        t -= m, cur_x = nxt[cur_x];
        if (vis[cur_x] == tim)
            t %= lst[cur_x] - t;
        vis[cur_x] = tim, lst[cur_x] = t;
    }
    while (t)
        cur_x = R(FindNext(cur_x, cur_y)), cur_y = C(cur_y + 1), t --;
}

inline void Modify(int x, int y)
{
    int pos = Jump(x, y);
    pii cur = mp(x, x);
    while (y)
    {
        y --;
        pii nxt = mp(INT_MAX, INT_MIN);
        for (int i = cur.xx + 1; i >= cur.xx - 1; i --)
        {
            int p = FindNext(i, y);
            if (p >= cur.xx && p <= cur.yy)
                nxt.xx = i;
        }
        for (int i = cur.yy - 1; i <= cur.yy + 1; i ++)
        {
            int p = FindNext(i, y);
            if (p >= cur.xx && p <= cur.yy)
                nxt.yy = i;
        }
        if (nxt.xx > nxt.yy)
            return ;
        cur = nxt;
    }
    if (cur.yy - cur.xx >= n)
        for (int i = 0; i < n; i ++)
            nxt[i] = pos;
    else
        for (int i = cur.xx; i <= cur.yy; i ++)
            nxt[R(i)] = pos;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read();
    for (int i = 0; i < n; i ++)
        for (int j = 0; j < m; j ++)
            a[i][j] = Read();
    for (int i = 0; i < n; i ++)
        nxt[i] = Jump(i, 0);
    q = Read();
    while (q --)
    {
        char opt[10];
        scanf("%s", opt);
        if (opt[0] == 'm')
            Move(Read()), printf("%d %d\n", cur_x + 1, cur_y + 1);
        else
        {
            int x = Read() - 1, y = Read() - 1;
            a[x][y] = Read();
            for (int i = x - 1; i <= x + 1; i ++)
                Modify(R(i), C(y - 1));
        }
    }
    return 0;
}

Embedding Enumeration

首先必须是一棵二叉树,不然无解。

暴力做法可以f(i,j)表示当前还剩 i 的子树没有放,并且已经放的长的一行减去短的一行长度为j

事实上 j 大多数时候是1,而不是 1 的时候也可以比较方便地特判掉。

#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;
const int mod = 1e9 + 7;

int n, ans, deg[MAXN], par[MAXN], nxt[MAXN], dis[MAXN], adj[MAXN][3], f[MAXN][4][4];
vector <int> seq;

inline void Addedge(int x, int y)
{
    if (deg[x] == 3 || deg[y] == 3)
        puts("0"), exit(0);
    adj[x][deg[x] ++] = y, adj[y][deg[y] ++] = x;
}

inline void DFS(int x)
{
    seq.pb(x);
    for (int i = 0; i < deg[x]; i ++)
        if (adj[x][i] ^ par[x])
            par[adj[x][i]] = x, DFS(adj[x][i]);
}

inline bool Find(int x, int y, int z, int &r)
{
    bool flg = false;
    r = -1;
    for (int i = 0; i < deg[x]; i ++)
        if ((adj[x][i] ^ y) && (adj[x][i] ^ z))
        {
            if (flg)
                return false;
            flg = true, r = adj[x][i];
        }
    return true;
}

inline bool Chain(int x)
{
    return deg[nxt[x]] == 1;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), Addedge(0, 1);
    for (int i = 1; i < n; i ++)
        Addedge(Read(), Read());
    par[0] = -1, DFS(0);
    for (int i = n; i; i --)
    {
        int x = seq[i], y;
        if (deg[x] == 2)
            Find(x, par[x], -1, y), nxt[x] = nxt[y], dis[x] = dis[y] + 1;
        else
            nxt[x] = x, dis[x] = 0;
    }
    f[0][1][0] = 1;
    for (auto x : seq)
        for (int i = 0; i <= deg[x]; i ++)
            for (int j = 0, y = i == deg[x] ? n + 1 : adj[x][i], z, u, v; j <= deg[y]; j ++)
                if (f[x][i][j])
                    if (Find(x, par[x], y, u) && Find(y, x, z = j == deg[y] ? n + 1 : adj[y][j], v))
                    {
                        if (~u && ~v)
                        {
                            while (deg[u] == 2 && deg[v] == 2)
                                Find(u, par[u], -1, u), Find(v, par[v], -1, v);
                            if (!Find(u, par[u], -1, u) || !Find(v, par[v], -1, v))
                                continue;
                        }
                        if (!~u && !~v)
                            ans = (ans + f[x][i][j]) % mod;
                        else
                        {
                            if (~v)
                                swap(u, v);
                            f[u][deg[u]][0] = (f[u][deg[u]][0] + f[x][i][j]) % mod;
                            for (int k = 0; k < deg[u]; k ++)
                                if (adj[u][k] ^ par[u])
                                    f[u][k][deg[adj[u][k]]] = (f[u][k][deg[adj[u][k]]] + f[x][i][j]) % mod;
                            if (Chain(u))
                            {
                                if (dis[u] >= 3 && (dis[u] & 1))
                                    ans = (ans + f[x][i][j]) % mod;
                            }
                            else
                                for (int t = 0, p = nxt[u], q, r; t < 2; t ++, p = par[p])
                                    for (int k = 0; k < deg[p]; k ++)
                                        if ((q = adj[p][k]) ^ par[p])
                                            for (int l = 0; l < deg[q]; l ++)
                                                if ((r = adj[q][l]) ^ p)
                                                    if (Chain(r) && dis[r] + 1 == dis[u] - t)
                                                        f[p][k][l] = (f[p][k][l] + f[x][i][j]) % mod;
                        }
                    }
    return printf("%d\n", ans), 0;
}

Faulty Factorial

分类讨论。

#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 LL Read()
{
    LL x = 0; int 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;
}

LL n;
int p, r;

inline int Qow(int x, int y)
{
    int r = 1;
    for (; y; y >>= 1, x = 1LL * x * x % p)
        if (y & 1)
            r = 1LL * r * x % p;
    return r;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), p = Read(), r = Read();
    if (!r)
    {
        if (n <= 2 || n < p)
            return puts("-1 -1"), 0;
        return printf("%d 1\n", 2 + (p == 2)), 0;
    }
    if (n >= p * 2)
        return puts("-1 -1"), 0;
    int fac = 1;
    for (int i = 1; i <= n; i ++)
        if (i ^ p)
            fac = 1LL * fac * i % p;
    int inv = Qow(fac, p - 2);
    if (n >= p)
        return printf("%d %d\n", p, 1LL * inv * r % p), 0;
    for (int i = 2; i <= n; i ++)
    {
        int v = 1LL * inv * i % p * r % p;
        if (v < i)
            return printf("%d %d\n", i, v), 0;
    }
    return puts("-1 -1"), 0;
}

Gambling Guide

f(x)表示 x 走到n的期望步数,那么显然 f(y)<f(x) 才会移动。

类似 Dijkstra 维护转移。

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

priority_queue <pair <double, int>> q;
double f[MAXN], sum[MAXN];
vector <int> adj[MAXN];
int n, m, cnt[MAXN];
bool vis[MAXN];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read();
    for (int i = 1, x, y; i <= m; i ++)
        x = Read(), y = Read(), adj[x].pb(y), adj[y].pb(x);
    f[n] = 0, q.push(mp(0, n));
    for (int i = 1; i <= n; i ++)
        sum[i] = adj[i].size();
    while (!q.empty())
    {
        int x = q.top().yy;
        q.pop();
        if (vis[x])
            continue;
        vis[x] = true;
        for (auto y : adj[x])
            if (!vis[y])
                cnt[y] ++, sum[y] += f[x], f[y] = sum[y] / cnt[y], q.push(mp(-f[y], y));
    }
    return printf("%lf\n", f[1]), 0;
}

Hidden Hierarchy

模拟。

#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, cnt, lim, siz[MAXN];
set <string> chd[MAXN];
vector <int> adj[MAXN];
map <int, string> rel;
map <string, int> idx;
bool fil[MAXN];

inline void DFS(int x)
{
    for (auto y : adj[x])
        DFS(y), siz[x] += siz[y];
}

inline void Solve(int x)
{
    if (fil[x])
        return ;
    bool flg = false;
    int val = 0;
    for (auto y : adj[x])
        if (!fil[y])
            val = max(val, siz[y]), flg = true;
    if (!flg)
    {
        cout << "  " << rel[x] << " " << siz[x] << endl;
        return ;
    }
    if (val >= lim)
    {
        cout << "- " << rel[x] << " " << siz[x] << endl;
        for (auto c : chd[x])
            Solve(idx[c]);
        return ;
    }
    else
    {
        cout << "+ " << rel[x] << " " << siz[x] << endl;
        return ;
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1; i <= n; i ++)
    {
        string str, pre;
        cin >> str;
        idx[str] = ++ cnt, rel[cnt] = str, siz[cnt] = Read(), pre = str, fil[cnt] = true;
        for (int i = str.length() - 1; ~i; i --)
            if (str[i] == '/')
            {
                string cur = str.substr(0, i + 1);
                if (idx.find(cur) == idx.end())
                {
                    idx[cur] = ++ cnt, rel[cnt] = cur;
                    adj[cnt].pb(cnt - 1), chd[cnt].insert(pre), pre = cur;
                }
                else
                {
                    adj[idx[cur]].pb(cnt), chd[idx[cur]].insert(pre);
                    break;
                }
            }
    }
    lim = Read(), DFS(idx["/"]), Solve(idx["/"]);
    return 0;
}

Intrinsic Interval

考虑一对相邻的数 (pi,pi+1) ,如果它们选了那么它们之间的数也必须选,求出值域在它们之间的出现位置 [l,r] ,那么让 i [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;
}

const int MAXN = 500005;

int n, m, ql, qr, cnt, tot, tim, top, seg_rot, d[MAXN], p[MAXN], q[MAXN], dfn[MAXN], low[MAXN], scc[MAXN], lch[MAXN], rch[MAXN], sta[MAXN], adj_min[MAXN], adj_max[MAXN], seg_min[MAXN], seg_max[MAXN];
vector <int> adj[MAXN], adv[MAXN];

inline void Modify(int x, int l, int r, int p, int u, int v)
{
    seg_min[x] = min(seg_min[x], u), seg_max[x] = max(seg_max[x], v);
    if (l == r)
        return ;
    int mid = l + r >> 1;
    return p <= mid ? Modify(x << 1, l, mid, p, u, v) : Modify(x << 1 | 1, mid + 1, r, p, u, v);
}

inline pii Query(int x, int l, int r, int ql, int qr)
{
    if (l == ql && r == qr)
        return mp(seg_min[x], seg_max[x]);
    int mid = l + r >> 1;
    if (qr <= mid)
        return Query(x << 1, l, mid, ql, qr);
    if (ql > mid)
        return Query(x << 1 | 1, mid + 1, r, ql, qr);
    pii L = Query(x << 1, l, mid, ql, mid), R = Query(x << 1 | 1, mid + 1, r, mid + 1, qr);
    return mp(min(L.xx, R.xx), max(L.yy, R.yy));
}

inline void Build(int &x, int l, int r)
{
    x = ++ tot;
    if (l == r)
        return (void)(adj[x].pb(l));
    int mid = l + r >> 1;
    Build(lch[x], l, mid), Build(rch[x], mid + 1, r), adj[x].pb(lch[x]), adj[x].pb(rch[x]);
}

inline void Addedge(int x, int l, int r, int ql, int qr, int p)
{
    if (l == ql && r == qr)
        return (void)(adj[p].pb(x));
    int mid = l + r >> 1;
    if (qr <= mid)
        Addedge(lch[x], l, mid, ql, qr, p);
    else if (ql > mid)
        Addedge(rch[x], mid + 1, r, ql, qr, p);
    else
        Addedge(lch[x], l, mid, ql, mid, p), Addedge(rch[x], mid + 1, r, mid + 1, qr, p);
}

inline void DFS(int x)
{
    dfn[x] = low[x] = ++ tim, sta[++ top] = 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])
    {
        cnt ++, adj_min[cnt] = n, adj_max[cnt] = 0;
        for (int k = 0; k ^ x; )
        {
            scc[k = sta[top --]] = cnt;
            if (k < n)
                adj_min[cnt] = min(adj_min[cnt], k), adj_max[cnt] = max(adj_max[cnt], k);
        }
    }
}

inline void ReBuild()
{
    for (int i = 1; i <= tot; i ++)
        for (auto j : adj[i])
            if (scc[i] ^ scc[j])
                adv[scc[i]].pb(scc[j]), d[scc[j]] ++;
    for (int i = 1; i <= cnt; i ++)
        if (!d[i])
            q[++ qr] = i;
    while (ql < qr)
    {
        int x = q[++ ql];
        for (auto y : adv[x])
            if (!-- d[y])
                q[++ qr] = y;
    }
    for (int i = qr; i; i --)
    {
        int x = q[i];
        for (auto y : adv[x])
            adj_min[x] = min(adj_min[x], adj_min[y]), adj_max[x] = max(adj_max[x], adj_max[y]);
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), tot = n - 1;
    mset(seg_min, 0x3f), mset(seg_max, 0);
    for (int i = 1; i <= n; i ++)
        p[i] = Read(), Modify(1, 1, n, p[i], i, i);
    if (n == 1)
    {
        m = Read();
        while (m --)
            puts("1 1");
        return 0;
    }
    Build(seg_rot, 1, n - 1);
    for (int i = 1; i < n; i ++)
    {
        int l = p[i], r = p[i + 1];
        if (l > r)
            swap(l, r);
        pii ret = Query(1, 1, n, l, r);
        Addedge(seg_rot, 1, n - 1, ret.xx, ret.yy - 1, i);
    }
    for (int i = 1; i <= tot; i ++)
        if (!dfn[i])
            DFS(i);
    ReBuild();
    mset(seg_min, 0x3f), mset(seg_max, 0);
    for (int i = 1; i < n; i ++)
        Modify(1, 1, n - 1, i, adj_min[scc[i]], adj_max[scc[i]]);
    m = Read();
    while (m --)
    {
        int l = Read(), r = Read();
        if (l == r)
            printf("%d %d\n", l, r);
        else
        {
            pii ret = Query(1, 1, n - 1, l, r - 1);
            printf("%d %d\n", ret.xx, ret.yy + 1);
        }
    }
    return 0;
}

Justified Jungle

暴力。

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

int n, siz[MAXN], cnt[MAXN];
vector <int> fac, ans, adj[MAXN];

inline void DFS(int x, int p)
{
    siz[x] = 1;
    for (auto y : adj[x])
        if (y ^ p)
            DFS(y, x), siz[x] += siz[y];
    if (x ^ 1)
        cnt[__gcd(siz[x], n)] ++;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1; i < n; i ++)
        if (n % i == 0)
            fac.pb(i);
    for (int i = 1, x, y; i < n; i ++)
        x = Read(), y = Read(), adj[x].pb(y), adj[y].pb(x);
    DFS(1, 0);
    for (int i = 0; i < fac.size(); i ++)
        for (int j = i + 1; j < fac.size(); j ++)
           if (fac[j] % fac[i] == 0)
               cnt[fac[i]] += cnt[fac[j]];
    for (auto x : fac)
        if (cnt[x] == n / x - 1)
            ans.pb(n / x - 1);
    reverse(ans.begin(), ans.end());
    for (auto x : ans)
        printf("%d ", x);
    putchar(10);
    return 0;
}

Kitchen Knobs

首先去掉所有位置都是相同数字的,然后差分,每次操作相当于某个位置加 x ,另一个位置减x

不难转化成:将所有数分成尽量多组,满足每组和为 0 ,答案是n减去组数。

贪心之后只有三种数了,暴力 DP 即可。

#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 = 505;

int n, b[MAXN], cnt[7], f[MAXN][MAXN][7], g[MAXN][MAXN][7];

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1; i <= n; i ++)
    {
        int a[7];
        a[0] = Read();
        for (int j = 1; j < 7; j ++)
            a[j] = a[j - 1] / 10 + a[j - 1] % 10 * 1000000;
        if (a[0] == a[1])
            i --, n --;
        else
            b[i] = max_element(a, a + 7) - a;
    }
    for (int i = 1; i <= n + 1; i ++)
        cnt[(b[i] - b[i - 1] + 7) % 7] ++;
    int ret = n + 1 - cnt[0];
    for (int i = 1, v; i < 4; i ++)
        v = min(cnt[i], cnt[7 - i]), ret -= v, cnt[i] -= v, cnt[7 - i] -= v;
    int x = cnt[1] ? 1 : 6, cx = cnt[1] ? cnt[1] : cnt[6], y = cnt[2] ? 2 : 5, cy = cnt[2] ? cnt[2] : cnt[5], z = cnt[3] ? 3 : 4, cz = cnt[3] ? cnt[3] : cnt[4];
    for (int i = 0; i <= cy; i ++)
        for (int j = 0; j <= cz; j ++)
            for (int k = 0; k < 7; k ++)
                f[i][j][k] = -1;
    f[0][0][0] = 0;
    for (int l = 0; l <= cx; l ++)
    {
        for (int i = 0; i <= cy; i ++)
            for (int j = 0; j <= cz; j ++)
                for (int k = 0; k < 7; k ++)
                    g[i][j][k] = f[i][j][k], f[i][j][k] = -1;
        for (int i = 0; i <= cy; i ++)
            for (int j = 0; j <= cz; j ++)
                for (int k = 0; k < 7; k ++)
                    if (~g[i][j][k])
                    {
                        if (l < cx)
                            f[i][j][(k + x) % 7] = max(f[i][j][(k + x) % 7], g[i][j][k] + ((k + x) % 7 == 0));
                        if (i < cy)
                            g[i + 1][j][(k + y) % 7] = max(g[i + 1][j][(k + y) % 7], g[i][j][k] + ((k + y) % 7 == 0));
                        if (j < cz)
                            g[i][j + 1][(k + z) % 7] = max(g[i][j + 1][(k + z) % 7], g[i][j][k] + ((k + z) % 7 == 0));
                    }
    }
    return printf("%d\n", ret - g[cy][cz][0]), 0;
}

Lunar Landscape

前缀和。

#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 = 3005;
const int N = 3002;

int n, a[MAXN][MAXN], b[MAXN][MAXN];
double ans;

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1; i <= n; i ++)
    {
        char opt[2];
        scanf("%s", opt);
        int x = Read(), y = Read(), z = Read();
        if (opt[0] == 'A')
            x += N / 2 - z / 2, y += N / 2 - z / 2, a[x][y] = max(a[x][y], z);
        else
            x += N / 2 - z / 2, y += N / 2, b[x][y] = max(b[x][y], z);
    }
    for (int i = 1; i <= N; i ++)
        for (int j = 1; j <= N; j ++)
            a[i][j] = max(max(a[i][j], a[i - 1][j - 1] - 1), max(a[i - 1][j] - 1, a[i][j - 1] - 1)), b[i][j] = max(max(b[i][j], b[i - 1][j] - 1), max(b[i - 1][j - 1] - 2, b[i - 1][j + 1] - 2));
    for (int i = 1; i <= N; i ++)
        for (int j = 1; j <= N; j ++)
            if (a[i][j])
                ans ++;
            else
            {
                if (b[i][j])
                    ans += 0.25;
                if (b[i][j + 1])
                    ans += 0.25;
                if (b[i][j] > 1 || b[i][j + 1] > 1)
                    ans += 0.25;
                if (b[i - 1][j] > 1 || b[i - 1][j + 1] > 1)
                    ans += 0.25;
            }
    return printf("%.2lf\n", ans), 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值