Loading [MathJax]/extensions/tex2jax.js

Codeforces Round #534 (Div. 1) – 解题报告

A – Grid game

竖的横的上下分开填。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1103A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200;
int n, ux, uy, dx, dy;
char str[MAX_N];
int main()
{
scanf("%s", str + 1), n = strlen(str + 1);
ux = 1, uy = 1, dx = 0, dy = 1;
for (int i = 1; i <= n; i++)
if (str[i] == '0')
printf("%d %d\n", ux, uy), uy = uy % 4 + 1;
else
printf("%d %d\n", (dx >> 1) + 3, dy), dx = (dx + 1) % 4, dy = (dy + 1) % 4 + 1;
return 0;
}
// CF1103A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200; int n, ux, uy, dx, dy; char str[MAX_N]; int main() { scanf("%s", str + 1), n = strlen(str + 1); ux = 1, uy = 1, dx = 0, dy = 1; for (int i = 1; i <= n; i++) if (str[i] == '0') printf("%d %d\n", ux, uy), uy = uy % 4 + 1; else printf("%d %d\n", (dx >> 1) + 3, dy), dx = (dx + 1) % 4, dy = (dy + 1) % 4 + 1; return 0; }
// CF1103A.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e5 + 200;

int n, ux, uy, dx, dy;
char str[MAX_N];

int main()
{
    scanf("%s", str + 1), n = strlen(str + 1);
    ux = 1, uy = 1, dx = 0, dy = 1;
    for (int i = 1; i <= n; i++)
        if (str[i] == '0')
            printf("%d %d\n", ux, uy), uy = uy % 4 + 1;
        else
            printf("%d %d\n", (dx >> 1) + 3, dy), dx = (dx + 1) % 4, dy = (dy + 1) % 4 + 1;
    return 0;
}

B – Game with modulo

一共有 60 次询问机会,我们可以分两个 30 次:第一个 30 次用来询问最高位前的一位,第二个 30 位用来补全我们对 \(a – 1\) 的猜测。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1103B.cpp
#include <bits/stdc++.h>
using namespace std;
char cmdlet[20];
bool readStatus() { return scanf("%s", cmdlet + 1), cmdlet[1] != 'e'; }
bool query(int x, int y)
{
printf("? %d %d\n", x, y), fflush(stdout);
scanf("%s", cmdlet + 1);
return cmdlet[1] == 'x';
}
void answer(int x) { printf("! %d\n", x), fflush(stdout); }
int main()
{
while (readStatus())
{
int highest_digit = -1;
for (int i = 0; i <= 30; i++)
if (query(i == 0 ? 0 : 1 << (i - 1), 1 << i))
{
highest_digit = i - 1;
break;
}
int ans = highest_digit == -1 ? 0 : (1 << highest_digit);
for (int i = highest_digit - 1; i >= 0; i--)
if (!query(ans, ans | (1 << i)))
ans |= (1 << i);
ans++, answer(ans);
}
return 0;
}
// CF1103B.cpp #include <bits/stdc++.h> using namespace std; char cmdlet[20]; bool readStatus() { return scanf("%s", cmdlet + 1), cmdlet[1] != 'e'; } bool query(int x, int y) { printf("? %d %d\n", x, y), fflush(stdout); scanf("%s", cmdlet + 1); return cmdlet[1] == 'x'; } void answer(int x) { printf("! %d\n", x), fflush(stdout); } int main() { while (readStatus()) { int highest_digit = -1; for (int i = 0; i <= 30; i++) if (query(i == 0 ? 0 : 1 << (i - 1), 1 << i)) { highest_digit = i - 1; break; } int ans = highest_digit == -1 ? 0 : (1 << highest_digit); for (int i = highest_digit - 1; i >= 0; i--) if (!query(ans, ans | (1 << i))) ans |= (1 << i); ans++, answer(ans); } return 0; }
// CF1103B.cpp
#include <bits/stdc++.h>

using namespace std;

char cmdlet[20];

bool readStatus() { return scanf("%s", cmdlet + 1), cmdlet[1] != 'e'; }

bool query(int x, int y)
{
    printf("? %d %d\n", x, y), fflush(stdout);
    scanf("%s", cmdlet + 1);
    return cmdlet[1] == 'x';
}

void answer(int x) { printf("! %d\n", x), fflush(stdout); }

int main()
{
    while (readStatus())
    {
        int highest_digit = -1;
        for (int i = 0; i <= 30; i++)
            if (query(i == 0 ? 0 : 1 << (i - 1), 1 << i))
            {
                highest_digit = i - 1;
                break;
            }
        int ans = highest_digit == -1 ? 0 : (1 << highest_digit);
        for (int i = highest_digit - 1; i >= 0; i--)
            if (!query(ans, ans | (1 << i)))
                ans |= (1 << i);
        ans++, answer(ans);
    }
    return 0;
}

C – Johnny Solving

神仙构造题!

我们可以考虑先来解决 PATH 的情况:我们可以直接进行暴力的 DFS。如果暴力 DFS 无解,那么可以说明此时搜索树的分叉已经超过了 \(k\),所以我们可以用这个性质来解决 CYCLES 的情况。如果分叉超过了 \(k\),我们要找到一个长度大于 3 且不为 3 的倍数的环,考虑一个子树的一个叶子 \(u\) 有除了回到父亲的两条返祖边,我们称这两个祖先为 \(a, b, dep[a] < dep[b]\),父亲称为 \(fa\)。我们可以证明 \(dep[b] – dep[a] + 2, dep[u] – dep[a] + 1, dep[u] – dep[b] + 1 \bmod 3\) 为三个不同的值,所以一定存在不为三的倍数的环。构造完成。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1103C.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 2.5e5 + 200, MAX_M = 5e5 + 200;
int n, m, k, head[MAX_N], current, dep[MAX_N], up[MAX_N];
bool flag;
vector<int> lf;
struct edge
{
int to, nxt;
} edges[MAX_M << 1];
void addpath(int src, int dst)
{
edges[current].to = dst, edges[current].nxt = head[src];
head[src] = current++;
}
void dfs(int u, int fa)
{
up[u] = fa, dep[u] = dep[fa] + 1;
if (dep[u] >= (n + k - 1) / k && (!flag))
{
flag = true, puts("PATH");
printf("%d\n", dep[u]);
for (int v = u; v; v = up[v])
printf("%d ", v);
return (void)(puts(""));
}
bool leaf = true;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (edges[i].to != fa && dep[edges[i].to] == 0)
dfs(edges[i].to, u), leaf = false;
if (leaf)
lf.push_back(u);
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &m, &k);
for (int i = 1, u, v; i <= m; i++)
scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
dfs(1, 0);
if (flag)
return 0;
puts("CYCLES");
for (int loop_idx = 1; loop_idx <= k; loop_idx++)
{
int pt = lf[loop_idx - 1];
flag = false;
vector<int> pos;
for (int i = head[pt]; i != -1; i = edges[i].nxt)
{
if (pos.size() != 2)
pos.push_back(edges[i].to);
if (edges[i].to == up[pt] || (dep[pt] - dep[edges[i].to] + 1) % 3 == 0)
continue;
printf("%d\n", dep[pt] - dep[edges[i].to] + 1);
for (int p = pt; p != up[edges[i].to]; p = up[p])
printf("%d ", p);
puts(""), flag = true;
break;
}
if (flag)
continue;
sort(pos.begin(), pos.end(), [](int a, int b) { return dep[a] < dep[b]; });
printf("%d\n", dep[pos[1]] - dep[pos[0]] + 1);
int p = pos[1], neck = pos[0];
while (p != up[neck])
printf("%d ", p), p = up[p];
puts("");
}
return 0;
}
// CF1103C.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 2.5e5 + 200, MAX_M = 5e5 + 200; int n, m, k, head[MAX_N], current, dep[MAX_N], up[MAX_N]; bool flag; vector<int> lf; struct edge { int to, nxt; } edges[MAX_M << 1]; void addpath(int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src]; head[src] = current++; } void dfs(int u, int fa) { up[u] = fa, dep[u] = dep[fa] + 1; if (dep[u] >= (n + k - 1) / k && (!flag)) { flag = true, puts("PATH"); printf("%d\n", dep[u]); for (int v = u; v; v = up[v]) printf("%d ", v); return (void)(puts("")); } bool leaf = true; for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].to != fa && dep[edges[i].to] == 0) dfs(edges[i].to, u), leaf = false; if (leaf) lf.push_back(u); } int main() { memset(head, -1, sizeof(head)); scanf("%d%d%d", &n, &m, &k); for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u); dfs(1, 0); if (flag) return 0; puts("CYCLES"); for (int loop_idx = 1; loop_idx <= k; loop_idx++) { int pt = lf[loop_idx - 1]; flag = false; vector<int> pos; for (int i = head[pt]; i != -1; i = edges[i].nxt) { if (pos.size() != 2) pos.push_back(edges[i].to); if (edges[i].to == up[pt] || (dep[pt] - dep[edges[i].to] + 1) % 3 == 0) continue; printf("%d\n", dep[pt] - dep[edges[i].to] + 1); for (int p = pt; p != up[edges[i].to]; p = up[p]) printf("%d ", p); puts(""), flag = true; break; } if (flag) continue; sort(pos.begin(), pos.end(), [](int a, int b) { return dep[a] < dep[b]; }); printf("%d\n", dep[pos[1]] - dep[pos[0]] + 1); int p = pos[1], neck = pos[0]; while (p != up[neck]) printf("%d ", p), p = up[p]; puts(""); } return 0; }
// CF1103C.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 2.5e5 + 200, MAX_M = 5e5 + 200;

int n, m, k, head[MAX_N], current, dep[MAX_N], up[MAX_N];
bool flag;
vector<int> lf;

struct edge
{
    int to, nxt;
} edges[MAX_M << 1];

void addpath(int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    head[src] = current++;
}

void dfs(int u, int fa)
{
    up[u] = fa, dep[u] = dep[fa] + 1;
    if (dep[u] >= (n + k - 1) / k && (!flag))
    {
        flag = true, puts("PATH");
        printf("%d\n", dep[u]);
        for (int v = u; v; v = up[v])
            printf("%d ", v);
        return (void)(puts(""));
    }
    bool leaf = true;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (edges[i].to != fa && dep[edges[i].to] == 0)
            dfs(edges[i].to, u), leaf = false;
    if (leaf)
        lf.push_back(u);
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1, u, v; i <= m; i++)
        scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
    dfs(1, 0);
    if (flag)
        return 0;
    puts("CYCLES");
    for (int loop_idx = 1; loop_idx <= k; loop_idx++)
    {
        int pt = lf[loop_idx - 1];
        flag = false;
        vector<int> pos;
        for (int i = head[pt]; i != -1; i = edges[i].nxt)
        {
            if (pos.size() != 2)
                pos.push_back(edges[i].to);
            if (edges[i].to == up[pt] || (dep[pt] - dep[edges[i].to] + 1) % 3 == 0)
                continue;
            printf("%d\n", dep[pt] - dep[edges[i].to] + 1);
            for (int p = pt; p != up[edges[i].to]; p = up[p])
                printf("%d ", p);
            puts(""), flag = true;
            break;
        }
        if (flag)
            continue;
        sort(pos.begin(), pos.end(), [](int a, int b) { return dep[a] < dep[b]; });
        printf("%d\n", dep[pos[1]] - dep[pos[0]] + 1);
        int p = pos[1], neck = pos[0];
        while (p != up[neck])
            printf("%d ", p), p = up[p];
        puts("");
    }
    return 0;
}

D – Professional layer

我们可以发现其 \(\gcd\) 的质因数不超过 12 个,所以我们可以在设计 DP 状态的时候来状压这个质因子即可,然后在算一个 \(i\) 表示集合大小。我们发现 \(i\) 可能会很大,然而我们已经知道这个质因子的个数不超过 12 个,所以我们可以把一些相同的数字给压缩起来,最后转移的时候批量转移。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// CF1103D.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, MAX_M = 12;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int n, m;
ll k, ai[MAX_N], ei[MAX_N], d, f[13][1 << MAX_M];
vector<ll> primes;
map<ll, vector<int> /**/> mp;
bool valid[1 << MAX_M];
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
int main()
{
scanf("%d%lld", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%lld", &ai[i]), d = gcd(ai[i], d);
for (int i = 1; i <= n; i++)
scanf("%lld", &ei[i]);
for (ll i = 2; 1LL * i * i <= d; i++)
if (d % i == 0)
{
primes.push_back(i);
while (d % i == 0)
d /= i;
}
if (d > 1)
primes.push_back(d);
m = primes.size();
for (int i = 1; i <= n; i++)
{
ll tmp = 1;
for (int j = 0; j < m; j++)
while (ai[i] % primes[j] == 0)
ai[i] /= primes[j], tmp *= primes[j];
mp[tmp].push_back(ei[i]);
}
memset(f, 0x3f, sizeof(f)), f[0][0] = 0;
ll ans = INF;
for (auto &curt : mp)
{
ll u = curt.first;
sort(curt.second.begin(), curt.second.end());
if (1LL * curt.second.size() > m)
curt.second.resize(k);
for (int stat = 0; stat < (1 << m); stat++)
{
ll tmp = u, acc = 1;
for (int j = 0; j < m; j++)
if (stat & (1 << j))
while (tmp % primes[j] == 0)
tmp /= primes[j], acc *= primes[j];
valid[stat] = (acc <= k);
}
for (auto cost : curt.second)
{
bool vis = false;
for (int i = m - 1; i >= 0; i--)
for (int stat = 0; stat < (1 << m); stat++)
if (f[i][stat] < INF)
for (int substat = (stat + 1) | stat; substat < (1 << m); substat = (substat + 1) | stat)
if (valid[substat ^ stat] && f[i + 1][substat] > f[i][stat] + cost)
vis = true, f[i + 1][substat] = f[i][stat] + cost;
// no where to relax;
if (!vis)
break;
}
}
for (int i = 0; i <= m; i++)
if (f[i][(1 << m) - 1] < INF)
ans = min(ans, 1LL * f[i][(1 << m) - 1] * i);
if (ans == INF)
puts("-1");
else
printf("%lld\n", ans);
return 0;
}
// CF1103D.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e6 + 200, MAX_M = 12; typedef long long ll; const ll INF = 0x3f3f3f3f3f3f3f3f; int n, m; ll k, ai[MAX_N], ei[MAX_N], d, f[13][1 << MAX_M]; vector<ll> primes; map<ll, vector<int> /**/> mp; bool valid[1 << MAX_M]; ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } int main() { scanf("%d%lld", &n, &k); for (int i = 1; i <= n; i++) scanf("%lld", &ai[i]), d = gcd(ai[i], d); for (int i = 1; i <= n; i++) scanf("%lld", &ei[i]); for (ll i = 2; 1LL * i * i <= d; i++) if (d % i == 0) { primes.push_back(i); while (d % i == 0) d /= i; } if (d > 1) primes.push_back(d); m = primes.size(); for (int i = 1; i <= n; i++) { ll tmp = 1; for (int j = 0; j < m; j++) while (ai[i] % primes[j] == 0) ai[i] /= primes[j], tmp *= primes[j]; mp[tmp].push_back(ei[i]); } memset(f, 0x3f, sizeof(f)), f[0][0] = 0; ll ans = INF; for (auto &curt : mp) { ll u = curt.first; sort(curt.second.begin(), curt.second.end()); if (1LL * curt.second.size() > m) curt.second.resize(k); for (int stat = 0; stat < (1 << m); stat++) { ll tmp = u, acc = 1; for (int j = 0; j < m; j++) if (stat & (1 << j)) while (tmp % primes[j] == 0) tmp /= primes[j], acc *= primes[j]; valid[stat] = (acc <= k); } for (auto cost : curt.second) { bool vis = false; for (int i = m - 1; i >= 0; i--) for (int stat = 0; stat < (1 << m); stat++) if (f[i][stat] < INF) for (int substat = (stat + 1) | stat; substat < (1 << m); substat = (substat + 1) | stat) if (valid[substat ^ stat] && f[i + 1][substat] > f[i][stat] + cost) vis = true, f[i + 1][substat] = f[i][stat] + cost; // no where to relax; if (!vis) break; } } for (int i = 0; i <= m; i++) if (f[i][(1 << m) - 1] < INF) ans = min(ans, 1LL * f[i][(1 << m) - 1] * i); if (ans == INF) puts("-1"); else printf("%lld\n", ans); return 0; }
// CF1103D.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e6 + 200, MAX_M = 12;

typedef long long ll;

const ll INF = 0x3f3f3f3f3f3f3f3f;

int n, m;
ll k, ai[MAX_N], ei[MAX_N], d, f[13][1 << MAX_M];
vector<ll> primes;
map<ll, vector<int> /**/> mp;
bool valid[1 << MAX_M];

ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

int main()
{
    scanf("%d%lld", &n, &k);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &ai[i]), d = gcd(ai[i], d);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &ei[i]);
    for (ll i = 2; 1LL * i * i <= d; i++)
        if (d % i == 0)
        {
            primes.push_back(i);
            while (d % i == 0)
                d /= i;
        }
    if (d > 1)
        primes.push_back(d);
    m = primes.size();
    for (int i = 1; i <= n; i++)
    {
        ll tmp = 1;
        for (int j = 0; j < m; j++)
            while (ai[i] % primes[j] == 0)
                ai[i] /= primes[j], tmp *= primes[j];
        mp[tmp].push_back(ei[i]);
    }
    memset(f, 0x3f, sizeof(f)), f[0][0] = 0;
    ll ans = INF;
    for (auto &curt : mp)
    {
        ll u = curt.first;
        sort(curt.second.begin(), curt.second.end());
        if (1LL * curt.second.size() > m)
            curt.second.resize(k);
        for (int stat = 0; stat < (1 << m); stat++)
        {
            ll tmp = u, acc = 1;
            for (int j = 0; j < m; j++)
                if (stat & (1 << j))
                    while (tmp % primes[j] == 0)
                        tmp /= primes[j], acc *= primes[j];
            valid[stat] = (acc <= k);
        }
        for (auto cost : curt.second)
        {
            bool vis = false;
            for (int i = m - 1; i >= 0; i--)
                for (int stat = 0; stat < (1 << m); stat++)
                    if (f[i][stat] < INF)
                        for (int substat = (stat + 1) | stat; substat < (1 << m); substat = (substat + 1) | stat)
                            if (valid[substat ^ stat] && f[i + 1][substat] > f[i][stat] + cost)
                                vis = true, f[i + 1][substat] = f[i][stat] + cost;
            // no where to relax;
            if (!vis)
                break;
        }
    }
    for (int i = 0; i <= m; i++)
        if (f[i][(1 << m) - 1] < INF)
            ans = min(ans, 1LL * f[i][(1 << m) - 1] * i);
    if (ans == INF)
        puts("-1");
    else
        printf("%lld\n", ans);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *