CodeForces Gym 101630简要题解

Archery Tournament

经过每条竖线的圆至多 logC 个,线段树套 set 维护。

#include 
#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 = 200005;

int n, m, x[MAXN], y[MAXN], opt[MAXN], l[MAXN << 1];
set <int> s[MAXN << 3];

inline void Insert(int x, int l, int r, int ql, int qr, int v)
{
    if (l == ql && r == qr)
        return (void)s[x].insert(v);
    int mid = l + r >> 1;
    if (qr <= mid)
        Insert(x << 1, l, mid, ql, qr, v);
    else if (ql > mid)
        Insert(x << 1 | 1, mid + 1, r, ql, qr, v);
    else
        Insert(x << 1, l, mid, ql, mid, v), Insert(x << 1 | 1, mid + 1, r, mid + 1, qr, v);
}

inline void Erase(int x, int l, int r, int ql, int qr, int v)
{
    if (l == ql && r == qr)
        return (void)s[x].erase(v);
    int mid = l + r >> 1;
    if (qr <= mid)
        Erase(x << 1, l, mid, ql, qr, v);
    else if (ql > mid)
        Erase(x << 1 | 1, mid + 1, r, ql, qr, v);
    else
        Erase(x << 1, l, mid, ql, mid, v), Erase(x << 1 | 1, mid + 1, r, mid + 1, qr, v);
}

inline int Query(int x, int l, int r, int p, int v)
{
    for (auto i : s[x])
        if (1LL * (::x[i] - ::x[v]) * (::x[i] - ::x[v]) + 1LL * (y[i] - y[v]) * (y[i] - y[v]) < 1LL * y[i] * y[i])
            return i;
    if (l == r)
        return 0;
    int mid = l + r >> 1;
    return p <= mid ? Query(x << 1, l, mid, p, v) : Query(x << 1 | 1, mid + 1, r, p, v);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1; i <= n; i ++)
    {
        opt[i] = Read(), x[i] = Read(), y[i] = Read();
        if (opt[i] == 1)
            l[++ m] = x[i] - y[i], l[++ m] = x[i] + y[i];
        else
            l[++ m] = x[i];
    }
    sort(l + 1, l + m + 1), m = unique(l + 1, l + m + 1) - l - 1;
    for (int i = 1, r; i <= n; i ++)
        if (opt[i] == 1)
            Insert(1, 1, m, lower_bound(l + 1, l + m + 1, x[i] - y[i]) - l, lower_bound(l + 1, l + m + 1, x[i] + y[i]) - l, i);
        else if (r = Query(1, 1, m, lower_bound(l + 1, l + m + 1, x[i]) - l, i))
            printf("%d\n", r), Erase(1, 1, m, lower_bound(l + 1, l + m + 1, x[r] - y[r]) - l, lower_bound(l + 1, l + m + 1, x[r] + y[r]) - l, r);
        else
            puts("-1");
    return 0;
}

Box

分类讨论。

#include 
#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 a, b, c, w, h, x, y;

inline bool Check(int a, int b, int c)
{
    x = b + c << 1, y = a + (c << 1);
    if ((x <= w && y <= h) || (x <= h && y <= w))
        return true;
    x = a + c, y = a + c + 3 * b;
    if ((x <= w && y <= h) || (x <= h && y <= w))
        return true;
    x = a + b + c, y = a + c + (b << 1);
    if ((x <= w && y <= h) || (x <= h && y <= w))
        return true;
    return false;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    a = Read(), b = Read(), c = Read(), w = Read(), h = Read();
    return puts(Check(a, b, c) || Check(a, c, b) || Check(b, a, c) || Check(b, c, a) || Check(c, a, b) || Check(c, b, a) ? "Yes" : "No"), 0;
}

Connections

只要让 1 能到所有点并且所有点能到 1 即可。

正反各DFS一遍。

#include 
#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  adj[MAXN], rev[MAXN];
int n, m, x[MAXN], y[MAXN];
bool vis[MAXN], ans[MAXN];

inline void DFS(int x, vector  *adj)
{
    vis[x] = true;
    for (auto e : adj[x])
        if (!vis[e.xx])
            ans[e.yy] = true, DFS(e.xx, adj);
}

inline void Solve()
{
    n = Read(), m = Read();
    for (int i = 1; i <= n; i ++)
        adj[i].clear(), rev[i].clear();
    for (int i = 1; i <= m; i ++)
        ans[i] = false, x[i] = Read(), y[i] = Read(), adj[x[i]].pb(mp(y[i], i)), rev[y[i]].pb(mp(x[i], i));
    for (int i = 1; i <= n; i ++)
        vis[i] = false;
    DFS(1, adj);
    for (int i = 1; i <= n; i ++)
        vis[i] = false;
    DFS(1, rev);
    for (int i = 1, cnt = m - (n << 1); i <= m && cnt; i ++)
        if (!ans[i])
            printf("%d %d\n", x[i], y[i]), cnt --;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Solve();
    return 0;
}

Designing the Toy

先斜着构造过去,然后再填满。

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

pii a[3];

inline void Print(int x, int y, int z)
{
    int b[3];
    b[a[0].yy] = x, b[a[1].yy] = y, b[a[2].yy] = z;
    printf("%d %d %d\n", b[0], b[1], b[2]);
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int i = 0; i < 3; i ++)
        a[i].xx = Read(), a[i].yy = 2 - i;
    sort(a, a + 3);
    if (a[2].xx > a[0].xx * a[1].xx)
        return puts("-1"), 0;
    printf("%d\n", a[2].xx);
    int cnt = 0;
    for (int i = 1; i <= a[1].xx; i ++)
        Print(i, min(i, a[0].xx), 0), cnt ++;
    for (int i = 1; i <= a[1].xx && cnt < a[2].xx; i ++)
        for (int j = 1; j <= a[0].xx && cnt < a[2].xx; j ++)
            if (j ^ min(i, a[0].xx))
                Print(i, j, 0), cnt ++;
    return 0;
}

Easy Quest

贪心。

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

int n, m, a[MAXN];
vector <int> ans;

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 1, x; i <= n; i ++)
        if ((x = Read()) > 0)
            a[x] ++;
        else if (!x)
            m ++;
        else if (!a[-x] && !m)
            return puts("No"), 0;
        else if (a[-x])
            a[-x] --;
        else
            m --, ans.pb(-x);
    while (m --)
        ans.pb(1);
    puts("Yes");
    for (auto x : ans)
        printf("%d ", x);
    putchar(10);
    return 0;
}

The Final Level

贪心。

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

vector > ans;
int x, y, n;

inline void Add(int &x, int &y, int nxt_x, int nxt_y, int cur)
{
    if (cur)
        ans.pb(mp(mp(x, nxt_y - n + 1), mp(x + n - 1, nxt_y)));
    else
        ans.pb(mp(mp(nxt_x, y + n - 1), mp(nxt_x - n + 1, y)));
    x = nxt_x, y = nxt_y;
}

inline void Solve()
{
    ans.clear(), x = Read(), y = Read(), n = Read();
    int cur_x = 0, cur_y = 0, flp_x = 0, flp_y = 0, cur = 0;
    if (x < 0)
        x = -x, flp_x = 1;
    if (y < 0)
        y = -y, flp_y = 1;
    while (x - cur_x >= n || y - cur_y >= n)
    {
        Add(cur_x, cur_y, min(x, cur_x + n - 1), min(y, cur_y + n - 1), cur);
        if (x - cur_x < y - cur_y)
            cur_y ++, cur = 0;
        else
            cur_x ++, cur = 1;
    }
    if (!cur)
        Add(cur_x, cur_y, x, cur_y + n - 1, cur);
    else
        Add(cur_x, cur_y, cur_x + n - 1, y, cur);
    printf("%d\n", ans.size());
    for (auto e : ans)
    {
        if (flp_x)
            e.xx.xx *= -1, e.yy.xx *= -1;
        if (flp_y)
            e.xx.yy *= -1, e.yy.yy *= -1;
        printf("%d %d %d %d\n", e.xx.xx, e.xx.yy, e.yy.xx, e.yy.yy);
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    for (int T = Read(); T; T --)
        Solve();
    return 0;
}

The Great Wall

二分,把每个位置的贡献算出来,然后扫描线。

#include 
#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 = 30005;

LL a[MAXN], b[MAXN], c[MAXN], f[MAXN], g[MAXN];
int n, m, k, p[MAXN], q[MAXN], bit[MAXN];

inline void Modify(int x)
{
    for (; x <= n; x += x & -x)
        bit[x] ++;
}

inline int Query(int x)
{
    int r = 0;
    for (; x; x -= x & -x)
        r += bit[x];
    return r;
}

inline LL Solve(LL mid)
{
    LL ret = 0;
    for (int i = 1; i <= n - m + 1; i ++)
        f[i] = b[i + m - 1] + a[i - 1] - a[i + m - 1] - b[i - 1], p[i] = i;
    sort(p + 1, p + n - m + 1 + 1, [&](const int &x, const int &y) { return f[x] < f[y]; });
    for (int i = n - m + 1, j = 1; i; i --)
    {
        while (j <= n - m + 1 && f[p[i]] + f[p[j]] <= mid)
            Modify(p[j ++]);
        ret += Query(n) - Query(p[i] + m - 1);
    }
    for (int i = 1; i <= n; i ++)
        bit[i] = 0;
    for (int i = 1; i <= n - m + 1; i ++)
        f[i] = c[i + m - 1] + a[i - 1] - b[i + m - 1] - b[i - 1], g[i] = b[i + m - 1] + b[i - 1] - a[i + m - 1] - c[i - 1], p[i] = q[i] = i;
    sort(p + 1, p + n - m + 1 + 1, [&](const int &x, const int &y) { return f[x] < f[y]; });
    sort(q + 1, q + n - m + 1 + 1, [&](const int &x, const int &y) { return g[x] < g[y]; });
    for (int i = n - m + 1, j = 1; i; i --)
    {
        while (j <= n - m + 1 && f[p[i]] + g[q[j]] <= mid)
            Modify(q[j ++]);
        ret += Query(p[i] + m - 1) - Query(p[i]);
    }
    for (int i = 1; i <= n; i ++)
        bit[i] = 0;
    return ret;
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read(), k = Read();
    for (int i = 1; i <= n; i ++)
        a[i] = Read() + a[i - 1];
    for (int i = 1; i <= n; i ++)
        b[i] = Read() + b[i - 1];
    for (int i = 1; i <= n; i ++)
        c[i] = Read() + c[i - 1];
    LL l = 0, r = c[n], ret = 0;
    while (l <= r)
    {
        LL mid = l + r >> 1;
        if (Solve(mid) >= k)
            ret = mid, r = mid - 1;
        else
            l = mid + 1;
    }
    return printf("%lld\n", ret + a[n]), 0;
}

Hack

先随 30000 a ,然后按照协方差逐位确定。

正确性见原题题解。

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

const int MAXN = 30005;
const int N = 30000;

LL n, a[MAXN], b[MAXN], c[MAXN], ret[MAXN], nxt[MAXN], cur[MAXN];
unsigned sed = 1;

inline LL Qul(LL x, LL y)
{
    return ((x * y - (LL)(((long double)x * y + 0.5) / n) * n) % n + n) % n;
}

inline unsigned Rand()
{
    sed ^= sed << 13;
    sed ^= sed >> 17;
    sed ^= sed << 5;
    return sed;
}

inline LL RandLL()
{
    return (LL)Rand() << 31 | Rand();
}

inline int Bits(LL x)
{
    return x ? 64 - __builtin_clzll(x) : 0;
}

inline int Mul(LL x, LL y)
{
    return (Bits(x) + 1) * (Bits(y) + 1);
}

inline double Cov(LL *a, LL *b)
{
    double ave_a = 0, ave_b = 0, ret = 0;
    for (int i = 1; i <= N; i ++)
        ave_a += a[i], ave_b += b[i];
    ave_a /= N, ave_b /= N;
    for (int i = 1; i <= N; i ++)
        ret += (a[i] - ave_a) * (b[i] - ave_b);
    return ret / N;
}

int main()
{
    n = Read();
    for (int i = 1; i <= N; i ++)
    {
        LL x = a[i] = RandLL() % n + 1;
        printf("? %lld\n", a[i]);
        fflush(stdout);
        cur[i] = Read(), ret[i] = 1;
        for (int j = 0; j < 60; j ++)
            cur[i] -= Mul(x, x), x = Qul(x, x);
    }
    LL r = 0;
    for (int j = 0; j <= 60; j ++)
    {
        bool all = true;
        for (int i = 1; i <= N && all; i ++)
            all &= !cur[i];
        if (all)
            return printf("! %lld\n", r), fflush(stdout), 0;
        for (int i = 1; i <= N; i ++)
            nxt[i] = Qul(a[i], a[i]), b[i] = Mul(ret[i], a[i]), c[i] = Mul(ret[i], nxt[i]);
        double x = Cov(cur, b), y = Cov(b, b), z = Cov(b, c);
        if (!j || abs(x - y) <= abs(x - z))
        {
            r |= 1LL << j;
            for (int i = 1; i <= N; i ++)
                cur[i] -= Mul(ret[i], a[i]), ret[i] = Qul(ret[i], a[i]);
        }
        for (int i = 1; i <= N; i ++)
            a[i] = nxt[i];
    }
    return printf("! %lld\n", r), fflush(stdout), 0;
}

Interactive Sort

将目前已经切开的偶数分成若干个集合,先用奇数去二分出所在集合,然后暴力分割。

因为数据随机所以是 O(nlogn)

#include 
#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 = 10005;

int n, m, eve[MAXN], odd[MAXN];
vector <int> u, v, vec[MAXN];

inline bool Compare(int x, int y)
{
    char opt[3];
    printf("? %d %d\n", x, y);
    fflush(stdout);
    scanf("%s", opt);
    return opt[0] == '<';
}

inline void Seperate(int bel, int x)
{
    u.clear(), v.clear();
    for (auto y : vec[bel])
        if (Compare(y, x))
            u.pb(y);
        else
            v.pb(y);
}

inline int Insert(int x)
{
    for (int i = m; i > x; i --)
        vec[i + 1] = vec[i];
    vec[x] = u, vec[x + 1] = v, m ++;
    int ret = 0;
    for (int i = 1; i <= x; i ++)
        ret += vec[i].size();
    return ret * 2 + 1;
}

int main()
{
    n = Read(), m = 1;
    if (n == 1)
    {
        puts("! 1");
        fflush(stdout);
        return 0;
    }
    for (int i = 1; i <= n >> 1; i ++)
        vec[1].pb(i);
    for (int i = 1; i <= n + 1 >> 1; i ++)
    {
        int L = 1, R = m, ret = 0, cnt = 0;
        while (L <= R)
        {
            int mid = L + R >> 1;
            if (Compare(vec[mid][0], i))
                ret = mid, L = mid + 1;
            else
                R = mid - 1;
        }
        if (!ret)
        {
            Seperate(1, i);
            if (u.empty())
                odd[i] = 1;
            else if (v.empty())
                odd[i] = u.size() * 2 + 1;
            else
                odd[i] = Insert(1);
        }
        else
        {
            for (int i = 1; i < ret; i ++)
                cnt += vec[i].size();
            Seperate(ret, i);
            if (v.empty())
            {
                if (ret == m)
                    odd[i] = n;
                else
                {
                    cnt += vec[ret].size();
                    Seperate(ret + 1, i);
                    if (u.empty())
                        odd[i] = cnt * 2 + 1;
                    else
                        odd[i] = Insert(ret + 1);
                }
            }
            else
                odd[i] = Insert(ret);
        }
    }
    int cur = 0;
    for (int i = 1; i <= m; i ++)
        for (auto j : vec[i])
            cur ++, eve[j] = cur * 2;
    printf("!");
    for (int i = 1; i <= n >> 1; i ++)
        printf(" %d", eve[i]);
    for (int i = 1; i <= n + 1 >> 1; i ++)
        printf(" %d", odd[i]);
    putchar(10), fflush(stdout);
    return 0;
}

Journey from Petersburg to Moscow

枚举一条边 e 作为最小权值边,其他边权 max(valivale,0) 跑最短路,最后答案加上 vale×k

走了大于 K 条和小于 K 条都显然不优。

#include 
#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 LL INF = 1LL << 60;

vector  adj[MAXN];
LL ans = INF, d[MAXN];
vector <int> val;
bool v[MAXN];
int n, m, k;

inline LL Solve(int c)
{
    priority_queue int>> q;
    for (int i = 1; i <= n; i ++)
        d[i] = INF, v[i] = false;
    d[1] = 0, q.push(mp(0, 1));
    while (!q.empty())
    {
        int x = q.top().yy;
        q.pop();
        if (v[x])
            continue;
        v[x] = true;
        for (auto e : adj[x])
            if (d[e.xx] > d[x] + max(0, e.yy - c))
                d[e.xx] = d[x] + max(0, e.yy - c), q.push(mp(-d[e.xx], e.xx));
    }
    return d[n];
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read(), k = Read(), val.pb(0);
    for (int i = 1, x, y, w; i <= m; i ++)
        x = Read(), y = Read(), w = Read(), adj[x].pb(mp(y, w)), adj[y].pb(mp(x, w)), val.pb(w);
    for (auto x : val)
        ans = min(ans, Solve(x) + 1LL * x * k);
    cout << ans << endl;
    return 0;
}

Knapsack Cryptosystem

nq23 时折半。

n 较大时,注意到 a1<q2n2 ,枚举 a1 前面的非零位和 r 的前 a1 的后导零个数位就可以确定 r ,之后直接贪心即可。

#include 
#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 unsigned long long uLL;
typedef pair <int, int> pii;

inline uLL Read()
{
    uLL 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;
}

const int MAXN = 65;
const int MAXM = 4194305;

pair  u[MAXM], v[MAXM], w[MAXM];
uLL c, a[MAXN], b[MAXN];
int n;

inline void Print(uLL x)
{
    for (int i = 0; i < n; i ++)
        putchar((x >> i & 1) + '0');
    putchar(10);
    exit(0);
}

inline void Brute(uLL x, uLL *b, pair  *r, int n)
{
    r[0] = mp(x, 0);
    for (int i = 0; i < n; i ++)
    {
        for (int j = 0; j < 1 << i; j ++)
            w[j] = r[j], w[j + (1 << i)] = mp(r[j].xx + b[i], r[j].yy | 1 << i);
        rotate(w + (1 << i), min_element(w + (1 << i), w + (1 << i + 1)), w + (1 << (i + 1)));
        merge(w, w + (1 << i), w + (1 << i), w + (1 << i + 1), r);
    }
}

inline void Brute()
{
    int m = n >> 1;
    Brute(0, b, u, m);
    for (int i = m; i < n; i ++)
        b[i] = -b[i];
    Brute(c, b + m, v, n - m);
    for (int i = 0, j = 0; i < 1 << m; i ++)
    {
        for (; j < 1 << n - m && v[j].xx < u[i].xx; j ++);
        if (j < 1 << n - m && u[i].xx == v[j].xx)
            Print(u[i].yy | v[j].yy << m);
    }
}

inline uLL Inv(uLL x)
{
    uLL ret = 0;
    for (int i = 0; i < 64; i ++)
    {
        uLL t = (ret | 1uLL << i) * x;
        if (i < 63)
            t &= (1uLL << i + 1) - 1;
        if (t == 1)
            ret |= 1uLL << i;
    }
    return ret;
}

inline void Solve()
{
    int k = 0;
    for (uLL tmp = b[0]; !(tmp & 1); tmp >>= 1, k ++);
    uLL inv = Inv(b[0] >> k);
    for (int i = 1; i < 1 << 65 - n - k; i ++)
        for (int j = 0; j < 1 << k; j ++)
        {
            uLL r = inv * i + ((uLL)j << 64 - k), d = c * r, cur = 0;
            for (int k = 0; k < n; k ++)
                a[k] = b[k] * r;
            for (int k = n - 1; ~k; k --)
                if (d >= a[k])
                    d -= a[k], cur |= 1uLL << k;
            if (!d)
                Print(cur);
        }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read();
    for (int i = 0; i < n; i ++)
        b[i] = Read();
    c = Read();
    if (n <= 44)
        Brute();
    else
        Solve();
    return 0;
}

Laminar Family

把所有用到的树边提取出来,发现是若干条链。

然后直接单调栈。

#include 
#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, top, a[MAXN], b[MAXN], dep[MAXN], sta[MAXN], deg[MAXN], tag[MAXN], par[MAXN], idx[MAXN], f[18][MAXN];
vector <int> seq, adj[MAXN], adv[MAXN], qry[MAXN];
bool vis[MAXN], chk[MAXN];

inline void DFS(int x)
{
    seq.pb(x), f[0][x] = par[x];
    for (int i = 1; i < 18; i ++)
        f[i][x] = f[i - 1][f[i - 1][x]];
    for (auto y : adj[x])
        if (y ^ par[x])
            dep[y] = dep[x] + 1, par[y] = x, DFS(y);
}

inline int LCA(int x, int y)
{
    if (dep[x] < dep[y])
        swap(x, y);
    if (dep[x] ^ dep[y])
        for (int i = 17; ~i; i --)
            if (dep[x] - dep[y] >> i & 1)
                x = f[i][x];
    if (x == y)
        return x;
    for (int i = 17; ~i; i --)
        if (f[i][x] ^ f[i][y])
            x = f[i][x], y = f[i][y];
    return f[0][x];
}

inline void Go(int x)
{
    seq.pb(x), vis[x] = true;
    for (auto y : adv[x])
        if (!vis[y])
            Go(y);
}

inline void Solve(int x)
{
    vector  vec;
    seq.clear(), Go(x);
    for (int i = 0; i < seq.size(); i ++)
        idx[seq[i]] = i;
    for (int i = 0; i < seq.size(); i ++)
        for (auto j : qry[seq[i]])
            vec.pb(mp(idx[a[j]], idx[b[j]]));
    for (int i = 0; i < vec.size(); i ++)
        if (vec[i].xx > vec[i].yy)
            swap(vec[i].xx, vec[i].yy);
    for (int i = 0; i < vec.size(); i ++)
        vec[i].yy *= -1;
    sort(vec.begin(), vec.end());
    for (int i = 0; i < vec.size(); i ++)
        vec[i].yy *= -1;
    top = 0;
    for (int i = 0; i < vec.size(); i ++)
    {
        for (; top && vec[i].yy > vec[sta[top]].yy; top --)
            if (vec[i].xx <= vec[sta[top]].yy)
                puts("No"), exit(0);
        sta[++ top] = i;
    }
}

int main()
{
#ifdef wxh010910
    freopen("data.in", "r", stdin);
#endif
    n = Read(), m = Read();
    for (int i = 1, x, y; i < n; i ++)
        x = Read(), y = Read(), adj[x].pb(y), adj[y].pb(x);
    DFS(1);
    for (int i = 1; i <= m; i ++)
        a[i] = Read(), b[i] = Read(), qry[a[i]].pb(i), tag[a[i]] ++, tag[b[i]] ++, tag[LCA(a[i], b[i])] -= 2;
    for (int i = n - 1; i; i --)
        tag[par[seq[i]]] += tag[seq[i]];
    for (int i = 2; i <= n; i ++)
        if (tag[i])
            adv[i].pb(par[i]), adv[par[i]].pb(i);
    for (int i = 1; i <= n; i ++)
        if (adv[i].size() > 2)
            return puts("No"), 0;
    for (int i = 1; i <= n; i ++)
        if (adv[i].size() == 1 && !vis[i])
            Solve(i);
    return puts("Yes"), 0;
}

你可能感兴趣的:(CodeForces Gym 101630简要题解)